From 497dd29e9ec4147dd8cc1c8ed83cb4e0b2ecbe20 Mon Sep 17 00:00:00 2001 From: Rachael Alexanderson Date: Wed, 10 Mar 2021 11:44:43 -0500 Subject: [PATCH] - fix more line endings --- common.h | 234 +- error.c | 870 ++--- error.h | 330 +- misc.c | 816 ++--- misc.h | 116 +- parse.c | 9690 +++++++++++++++++++++++++-------------------------- parse.h | 82 +- pcode.c | 3222 ++++++++--------- pcode.h | 1006 +++--- strlist.c | 852 ++--- strlist.h | 76 +- symbol.c | 1214 +++---- symbol.h | 262 +- token.c | 3172 ++++++++--------- token.h | 358 +- zcommon.acs | 30 +- zwvars.acs | 16 +- 17 files changed, 11173 insertions(+), 11173 deletions(-) diff --git a/common.h b/common.h index 343d545..c4ba765 100644 --- a/common.h +++ b/common.h @@ -1,117 +1,117 @@ - -//************************************************************************** -//** -//** common.h -//** -//************************************************************************** - -#ifndef __COMMON_H__ -#define __COMMON_H__ - -// HEADER FILES ------------------------------------------------------------ - -// MACROS ------------------------------------------------------------------ - -#define ARRAY_SIZE(a) (sizeof(a)/sizeof(*(a))) -#ifndef TRUE -#define TRUE 1 -#endif -#ifndef FALSE -#define FALSE 0 -#endif -#ifndef YES -#define YES 1 -#endif -#ifndef NO -#define NO 0 -#endif -// Increased limits - Ty 03jan2000 -// 32 is okay -#define MAX_IDENTIFIER_LENGTH 32 -// 32k long quoted string should be okay -#define MAX_QUOTED_LENGTH 32768 -// 512 max file name is okay in DOS/Win -#define MAX_FILE_NAME_LENGTH 512 -// Was 64 -#define MAX_SCRIPT_COUNT 1000 -// Was 32 -#define MAX_MAP_VARIABLES 128 -// Left alone--there's something in the docs about this... -// [RH] Bumped up to 20 for fun. -#define MAX_SCRIPT_VARIABLES 20 -// Was 64 -#define MAX_WORLD_VARIABLES 256 -// [RH] New -#define MAX_GLOBAL_VARIABLES 64 -// Was 128 -#define MAX_STRINGS 32768 -// Don't know what this is -#define DEFAULT_OBJECT_SIZE 65536 -// Added Ty 07Jan2000 for error details -#define MAX_STATEMENT_LENGTH 4096 - -#define MAX_FUNCTION_COUNT 8192 - -#define MAX_IMPORTS 256 - -#define MAX_SCRIPT_ARRAYS 255 - -// Max number of include paths the user can specify -// This includes the "working directory"! -#define MAX_INCLUDE_PATHS 16 - -// Maximum number of translations that can be used -#define MAX_TRANSLATIONS 32 - -enum -{ - STRLIST_PICS, - STRLIST_FUNCTIONS, - STRLIST_MAPVARS, - STRLIST_NAMEDSCRIPTS, - - NUM_STRLISTS -}; - -// These are just defs and have not been messed with -#define ASCII_SPACE 32 -#define ASCII_QUOTE 34 -#define ASCII_UNDERSCORE 95 -#define EOF_CHARACTER 127 -#ifdef __NeXT__ -#define DIRECTORY_DELIMITER "/" -#define DIRECTORY_DELIMITER_CHAR ('/') -#else -#define DIRECTORY_DELIMITER "\\" -#define DIRECTORY_DELIMITER_CHAR ('\\') -#endif - - - -#define MAKE4CC(a,b,c,d) ((a)|((b)<<8)|((c)<<16)|((d)<<24)) - -// TYPES ------------------------------------------------------------------- - -typedef unsigned int boolean; -typedef unsigned char byte; -typedef signed char S_BYTE; -typedef unsigned char U_BYTE; -typedef signed short S_WORD; -typedef unsigned short U_WORD; -typedef int S_INT; -typedef unsigned int U_INT; -// typedef signed long S_LONG; -// typedef unsigned long U_LONG; - -enum ImportModes -{ - IMPORT_None, - IMPORT_Importing, - IMPORT_Exporting -}; - -// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- - -// PUBLIC DATA DECLARATIONS ------------------------------------------------ - -#endif + +//************************************************************************** +//** +//** common.h +//** +//************************************************************************** + +#ifndef __COMMON_H__ +#define __COMMON_H__ + +// HEADER FILES ------------------------------------------------------------ + +// MACROS ------------------------------------------------------------------ + +#define ARRAY_SIZE(a) (sizeof(a)/sizeof(*(a))) +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif +#ifndef YES +#define YES 1 +#endif +#ifndef NO +#define NO 0 +#endif +// Increased limits - Ty 03jan2000 +// 32 is okay +#define MAX_IDENTIFIER_LENGTH 32 +// 32k long quoted string should be okay +#define MAX_QUOTED_LENGTH 32768 +// 512 max file name is okay in DOS/Win +#define MAX_FILE_NAME_LENGTH 512 +// Was 64 +#define MAX_SCRIPT_COUNT 1000 +// Was 32 +#define MAX_MAP_VARIABLES 128 +// Left alone--there's something in the docs about this... +// [RH] Bumped up to 20 for fun. +#define MAX_SCRIPT_VARIABLES 20 +// Was 64 +#define MAX_WORLD_VARIABLES 256 +// [RH] New +#define MAX_GLOBAL_VARIABLES 64 +// Was 128 +#define MAX_STRINGS 32768 +// Don't know what this is +#define DEFAULT_OBJECT_SIZE 65536 +// Added Ty 07Jan2000 for error details +#define MAX_STATEMENT_LENGTH 4096 + +#define MAX_FUNCTION_COUNT 8192 + +#define MAX_IMPORTS 256 + +#define MAX_SCRIPT_ARRAYS 255 + +// Max number of include paths the user can specify +// This includes the "working directory"! +#define MAX_INCLUDE_PATHS 16 + +// Maximum number of translations that can be used +#define MAX_TRANSLATIONS 32 + +enum +{ + STRLIST_PICS, + STRLIST_FUNCTIONS, + STRLIST_MAPVARS, + STRLIST_NAMEDSCRIPTS, + + NUM_STRLISTS +}; + +// These are just defs and have not been messed with +#define ASCII_SPACE 32 +#define ASCII_QUOTE 34 +#define ASCII_UNDERSCORE 95 +#define EOF_CHARACTER 127 +#ifdef __NeXT__ +#define DIRECTORY_DELIMITER "/" +#define DIRECTORY_DELIMITER_CHAR ('/') +#else +#define DIRECTORY_DELIMITER "\\" +#define DIRECTORY_DELIMITER_CHAR ('\\') +#endif + + + +#define MAKE4CC(a,b,c,d) ((a)|((b)<<8)|((c)<<16)|((d)<<24)) + +// TYPES ------------------------------------------------------------------- + +typedef unsigned int boolean; +typedef unsigned char byte; +typedef signed char S_BYTE; +typedef unsigned char U_BYTE; +typedef signed short S_WORD; +typedef unsigned short U_WORD; +typedef int S_INT; +typedef unsigned int U_INT; +// typedef signed long S_LONG; +// typedef unsigned long U_LONG; + +enum ImportModes +{ + IMPORT_None, + IMPORT_Importing, + IMPORT_Exporting +}; + +// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- + +// PUBLIC DATA DECLARATIONS ------------------------------------------------ + +#endif diff --git a/error.c b/error.c index 7d32458..98a3af7 100644 --- a/error.c +++ b/error.c @@ -1,435 +1,435 @@ - -//************************************************************************** -//** -//** error.c -//** -//************************************************************************** - -// HEADER FILES ------------------------------------------------------------ - -#include -#include -#include -#include -#include "common.h" -#include "error.h" -#include "token.h" -#include "misc.h" - -// MACROS ------------------------------------------------------------------ - -#define ERROR_FILE_NAME "acs.err" - -// TYPES ------------------------------------------------------------------- - -typedef enum -{ - ERRINFO_GCC, - ERRINFO_VCC -} errorInfo_e; - -// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- - -// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- - -// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- - -static char *ErrorText(error_t error); -static char *ErrorFileName(void); -static void eprintf(const char *fmt, ...); -static void veprintf(const char *fmt, va_list args); - -// EXTERNAL DATA DECLARATIONS ---------------------------------------------- - -extern char acs_SourceFileName[MAX_FILE_NAME_LENGTH]; - -// PUBLIC DATA DEFINITIONS ------------------------------------------------- - -// PRIVATE DATA DEFINITIONS ------------------------------------------------ - -static struct -{ - error_t number; - char *name; -} ErrorNames[] = -{ - { ERR_MISSING_SEMICOLON, "Missing semicolon." }, - { ERR_MISSING_LPAREN, "Missing '('." }, - { ERR_MISSING_RPAREN, "Missing ')'." }, - { ERR_MISSING_LBRACE, "Missing '{'." }, - { ERR_MISSING_SCRIPT_NUMBER, "Missing script number." }, - { ERR_IDENTIFIER_TOO_LONG, "Identifier too long." }, - { ERR_STRING_TOO_LONG, "String too long." }, - { ERR_FILE_NAME_TOO_LONG, "File name too long.\nFile: \"%s\"" }, - { ERR_BAD_CHARACTER, "Bad character in script text." }, - { ERR_BAD_CHARACTER_CONSTANT, "Bad character constant in script text." }, - { ERR_ALLOC_PCODE_BUFFER, "Failed to allocate PCODE buffer." }, - { ERR_PCODE_BUFFER_OVERFLOW, "PCODE buffer overflow." }, - { ERR_TOO_MANY_SCRIPTS, "Too many scripts." }, - { ERR_TOO_MANY_FUNCTIONS, "Too many functions." }, - { ERR_SAVE_OBJECT_FAILED, "Couldn't save object file." }, - { ERR_MISSING_LPAREN_SCR, "Missing '(' in script definition." }, - { ERR_INVALID_IDENTIFIER, "Invalid identifier." }, - { ERR_REDEFINED_IDENTIFIER, "%s : Redefined identifier." }, - { ERR_MISSING_COMMA, "Missing comma." }, - { ERR_BAD_VAR_TYPE, "Invalid variable type." }, - { ERR_BAD_RETURN_TYPE, "Invalid return type." }, - { ERR_TOO_MANY_SCRIPT_ARGS, "Too many script arguments." }, - { ERR_MISSING_LBRACE_SCR, "Missing opening '{' in script definition." }, - { ERR_MISSING_RBRACE_SCR, "Missing closing '}' in script definition." }, - { ERR_TOO_MANY_MAP_VARS, "Too many map variables." }, - { ERR_TOO_MANY_SCRIPT_VARS, "Too many script variables." }, - { ERR_TOO_MANY_FUNCTION_VARS, "Too many function variables." }, - { ERR_TOO_MANY_SCRIPT_ARRAYS, "Too many script arrays." }, - { ERR_TOO_MANY_FUNCTION_ARRAYS, "Too many function arrays." }, - { ERR_MISSING_WVAR_INDEX, "Missing index in world variable declaration." }, - { ERR_MISSING_GVAR_INDEX, "Missing index in global variable declaration." }, - { ERR_BAD_WVAR_INDEX, "World variable index out of range." }, - { ERR_MISSING_WVAR_COLON, "Missing colon in world variable declaration." }, - { ERR_MISSING_GVAR_COLON, "Missing colon in global variable declaration." }, - { ERR_MISSING_SPEC_VAL, "Missing value in special declaration." }, - { ERR_MISSING_SPEC_COLON, "Missing colon in special declaration." }, - { ERR_MISSING_SPEC_ARGC, "Missing argument count in special declaration." }, - { ERR_CANT_READ_FILE, "Couldn't read file.\nFile: \"%s\"" }, - { ERR_CANT_OPEN_FILE, "Couldn't open file.\nFile: \"%s\"" }, - { ERR_CANT_OPEN_DBGFILE, "Couldn't open debug file." }, - { ERR_INVALID_DIRECTIVE, "Invalid directive." }, - { ERR_BAD_DEFINE, "Non-numeric constant found in #define." }, - { ERR_INCL_NESTING_TOO_DEEP, "Include nesting too deep.\nUnable to include file \"%s\"." }, - { ERR_STRING_LIT_NOT_FOUND, "String literal not found." }, - { ERR_INVALID_DECLARATOR, "Invalid declarator." }, - { ERR_BAD_LSPEC_ARG_COUNT, "Incorrect number of special arguments." }, - { ERR_BAD_ARG_COUNT, "Incorrect number of arguments." }, - { ERR_UNKNOWN_IDENTIFIER, "%s : Identifier has not been declared." }, - { ERR_MISSING_COLON, "Missing colon." }, - { ERR_BAD_EXPR, "Syntax error in expression." }, - { ERR_BAD_CONST_EXPR, "Syntax error in constant expression." }, - { ERR_DIV_BY_ZERO_IN_CONST_EXPR, "Division by zero in constant expression." }, - { ERR_NO_DIRECT_VER, "Internal function has no direct version." }, - { ERR_ILLEGAL_EXPR_IDENT, "%s : Illegal identifier in expression." }, - { ERR_EXPR_FUNC_NO_RET_VAL, "Function call in expression has no return value." }, - { ERR_MISSING_ASSIGN_OP, "Missing assignment operator." }, - { ERR_INCDEC_OP_ON_NON_VAR, "'++' or '--' used on a non-variable." }, - { ERR_MISSING_RBRACE, "Missing '}' at end of compound statement." }, - { ERR_INVALID_STATEMENT, "Invalid statement." }, - { ERR_BAD_DO_STATEMENT, "Do statement not followed by 'while' or 'until'." }, - { ERR_BAD_SCRIPT_DECL, "Bad script declaration." }, - { ERR_CASE_OVERFLOW, "Internal Error: Case stack overflow." }, - { ERR_BREAK_OVERFLOW, "Internal Error: Break stack overflow." }, - { ERR_CONTINUE_OVERFLOW, "Internal Error: Continue stack overflow." }, - { ERR_STATEMENT_OVERFLOW, "Internal Error: Statement overflow." }, - { ERR_MISPLACED_BREAK, "Misplaced BREAK statement." }, - { ERR_MISPLACED_CONTINUE, "Misplaced CONTINUE statement." }, - { ERR_CASE_NOT_IN_SWITCH, "CASE must appear in switch statement." }, - { ERR_DEFAULT_NOT_IN_SWITCH, "DEFAULT must appear in switch statement." }, - { ERR_MULTIPLE_DEFAULT, "Only 1 DEFAULT per switch allowed." }, - { ERR_EXPR_STACK_OVERFLOW, "Expression stack overflow." }, - { ERR_EXPR_STACK_EMPTY, "Tried to POP empty expression stack." }, - { ERR_UNKNOWN_CONST_EXPR_PCD, "Unknown PCD in constant expression." }, - { ERR_BAD_RADIX_CONSTANT, "Radix out of range in integer constant." }, - { ERR_BAD_ASSIGNMENT, "Syntax error in multiple assignment statement." }, - { ERR_OUT_OF_MEMORY, "Out of memory." }, - { ERR_TOO_MANY_STRINGS, "Too many strings. Current max is %d" }, - { ERR_UNKNOWN_PRTYPE, "Unknown cast type in print statement." }, - { ERR_SCRIPT_OUT_OF_RANGE, "Script number must be between 1 and 32767." }, - { ERR_MISSING_PARAM, "Missing required argument." }, - { ERR_SCRIPT_ALREADY_DEFINED, "Script already has a body." }, - { ERR_FUNCTION_ALREADY_DEFINED, "Function already has a body." }, - { ERR_PARM_MUST_BE_VAR, "Parameter must be a variable." }, - { ERR_MISSING_FONT_NAME, "Missing font name." }, - { ERR_MISSING_LBRACE_FONTS, "Missing opening '{' in font list." }, - { ERR_MISSING_RBRACE_FONTS, "Missing closing '}' in font list." }, - { ERR_NOCOMPACT_NOT_HERE, "#nocompact must appear before any scripts." }, - { ERR_MISSING_ASSIGN, "Missing '='." }, - { ERR_PREVIOUS_NOT_VOID, "Previous use of function expected a return value." }, - { ERR_MUST_RETURN_A_VALUE, "Function must return a value." }, - { ERR_MUST_NOT_RETURN_A_VALUE, "Void functions cannot return a value." }, - { ERR_SUSPEND_IN_FUNCTION, "Suspend cannot be used inside a function." }, - { ERR_TERMINATE_IN_FUNCTION, "Terminate cannot be used inside a function." }, - { ERR_RESTART_IN_FUNCTION, "Restart cannot be used inside a function." }, - { ERR_RETURN_OUTSIDE_FUNCTION, "Return can only be used inside a function." }, - { ERR_FUNC_ARGUMENT_COUNT, "Function %s should have %d argument%s." }, - { ERR_EOF, "Unexpected end of file." }, - { ERR_UNDEFINED_FUNC, "Function %s is used but not defined." }, - { ERR_TOO_MANY_ARRAY_DIMS, "Too many array dimensions." }, - { ERR_TOO_MANY_ARRAY_INIT, "Too many initializers for array." }, - { ERR_MISSING_LBRACKET, "Missing '['." }, - { ERR_MISSING_RBRACKET, "Missing ']'." }, - { ERR_ZERO_DIMENSION, "Arrays cannot have a dimension of zero." }, - { ERR_TOO_MANY_DIM_USED, "%s only has %d dimensions." }, - { ERR_TOO_FEW_DIM_USED, "%s access needs %d more dimensions." }, - { ERR_ARRAY_MAPVAR_ONLY, "Only map variables can be arrays." }, - { ERR_NOT_AN_ARRAY, "%s is not an array." }, - { ERR_MISSING_LBRACE_ARR, "Missing opening '{' in array initializer." }, - { ERR_MISSING_RBRACE_ARR, "Missing closing '}' in array initializer." }, - { ERR_LATENT_IN_FUNC, "Latent functions cannot be used inside functions." }, - { ERR_LOCAL_VAR_SHADOWED, "A global identifier already has this name." }, - { ERR_MULTIPLE_IMPORTS, "You can only #import one file." }, - { ERR_IMPORT_IN_EXPORT, "You cannot #import from inside an imported file." }, - { ERR_EXPORTER_NOT_FLAGGED, "A file that you #import must have a #library line." }, - { ERR_TOO_MANY_IMPORTS, "Too many files imported." }, - { ERR_NO_NEED_ARRAY_SIZE, "Only map arrays need a size." }, - { ERR_NO_MULTIDIMENSIONS, "Only map arrays can have more than one dimension." }, - { ERR_NEED_ARRAY_SIZE, "Missing array size." }, - { ERR_DISCONNECT_NEEDS_1_ARG, "Disconnect scripts must have 1 argument." }, - { ERR_UNCLOSED_WITH_ARGS, "Most special scripts must not have arguments." }, - { ERR_NOT_A_CHAR_ARRAY, "%s has %d dimensions. Use %d subscripts to get a char array." }, - { ERR_CANT_FIND_INCLUDE, "Couldn't find include file \"%s\"." }, - { ERR_SCRIPT_NAMED_NONE, "Scripts may not be named \"None\"." }, - { ERR_HEXEN_COMPAT, "Attempt to use feature not supported by Hexen." }, - { ERR_NOT_HEXEN, "Cannot save; new features are not compatible with Hexen." }, - { ERR_SPECIAL_RANGE, "Line specials with values higher than 255 require #nocompact." }, - { ERR_EVENT_NEEDS_3_ARG, "Event scripts must have 3 arguments." }, // [BB] - { ERR_LIBRARY_NOT_FIRST, "#library must come before anything else." }, - { ERR_NONE, NULL } -}; - -static FILE *ErrorFile; -static int ErrorCount; -static errorInfo_e ErrorFormat; -static char *ErrorSourceName; -static int ErrorSourceLine; - -// CODE -------------------------------------------------------------------- - -//========================================================================== -// -// ERR_ErrorAt -// -//========================================================================== - -void ERR_ErrorAt(char *source, int line) -{ - ErrorSourceName = source; - ErrorSourceLine = line; -} - -//========================================================================== -// -// ERR_Error -// -//========================================================================== - -void ERR_Error(error_t error, boolean info, ...) -{ - va_list args; - va_start(args, info); - ERR_ErrorV(error, info, args); - va_end(args); -} - -//========================================================================== -// -// ERR_Exit -// -//========================================================================== - -void ERR_Exit(error_t error, boolean info, ...) -{ - va_list args; - va_start(args, info); - ERR_ErrorV(error, info, args); - va_end(args); - ERR_Finish(); -} - -//========================================================================== -// -// ERR_Finish -// -//========================================================================== - -void ERR_Finish(void) -{ - if(ErrorFile) - { - fclose(ErrorFile); - ErrorFile = NULL; - } - if(ErrorCount) - { - exit(1); - } -} - -//========================================================================== -// -// ShowError -// -//========================================================================== - -void ERR_ErrorV(error_t error, boolean info, va_list args) -{ - char *text; - boolean showLine = NO; - static boolean showedInfo = NO; - - if(!ErrorFile) - { - ErrorFile = fopen(ErrorFileName(), "w"); - } - if(ErrorCount == 0) - { - fprintf(stderr, "\n**** ERROR ****\n"); - } - else if(ErrorCount == 100) - { - eprintf("More than 100 errors. Can't continue.\n"); - ERR_Finish(); - } - ErrorCount++; - if(info == YES) - { - char *source; - int line; - - if(ErrorSourceName) - { - source = ErrorSourceName; - line = ErrorSourceLine; - ErrorSourceName = NULL; - } - else - { - source = tk_SourceName; - line = tk_Line; - showLine = YES; - } - if(showedInfo == NO) - { // Output info compatible with older ACCs - // for editors that expect it. - showedInfo = YES; - eprintf("Line %d in file \"%s\" ...\n", line, source); - } - if(ErrorFormat == ERRINFO_GCC) - { - eprintf("%s:%d: ", source, line); - } - else - { - eprintf("%s(%d) : ", source, line); - if(error != ERR_NONE) - { - eprintf("error %04d: ", error); - } - } - } - if(error != ERR_NONE) - { - text = ErrorText(error); - if(text != NULL) - { - veprintf(text, args); - } - eprintf("\n"); - if(showLine) - { - // deal with master source line and position indicator - Ty 07jan2000 - MasterSourceLine[MasterSourcePos] = '\0'; // pre-incremented already - eprintf("> %s\n", MasterSourceLine); // the string - eprintf(">%*s\n", MasterSourcePos, "^"); // pointer to error - } - } -#if 0 - else - { - va_list args2; - va_start(va_arg(args,char*), args2); - veprintf(va_arg(args,char*), args2); - va_end(args2); - } -#endif -} - -//========================================================================== -// -// ERR_RemoveErrorFile -// -//========================================================================== - -void ERR_RemoveErrorFile(void) -{ - remove(ErrorFileName()); -} - -//========================================================================== -// -// ERR_ErrorFileName -// -//========================================================================== - -static char *ErrorFileName(void) -{ - static char errFileName[MAX_FILE_NAME_LENGTH]; - - strcpy(errFileName, acs_SourceFileName); - if(MS_StripFilename(errFileName) == NO) - { - strcpy(errFileName, ERROR_FILE_NAME); - } - else - { - strcat(errFileName, ERROR_FILE_NAME); - } - return errFileName; -} - -//========================================================================== -// -// ErrorText -// -//========================================================================== - -static char *ErrorText(error_t error) -{ - int i; - - for(i = 0; ErrorNames[i].number != ERR_NONE; i++) - { - if(error == ErrorNames[i].number) - { - return ErrorNames[i].name; - } - } - return NULL; -} - -//========================================================================== -// -// eprintf -// -//========================================================================== - -static void eprintf(const char *fmt, ...) -{ - va_list args; - va_start(args, fmt); - veprintf(fmt, args); - va_end(args); -} - -//========================================================================== -// -// veprintf -// -//========================================================================== - -static void veprintf(const char *fmt, va_list args) -{ -#ifdef va_copy - va_list copy; - va_copy(copy, args); -#endif - vfprintf(stderr, fmt, args); - if(ErrorFile) - { -#ifdef va_copy - vfprintf(ErrorFile, fmt, copy); -#else - vfprintf(ErrorFile, fmt, args); -#endif - } -#ifdef va_copy - va_end(copy); -#endif -} + +//************************************************************************** +//** +//** error.c +//** +//************************************************************************** + +// HEADER FILES ------------------------------------------------------------ + +#include +#include +#include +#include +#include "common.h" +#include "error.h" +#include "token.h" +#include "misc.h" + +// MACROS ------------------------------------------------------------------ + +#define ERROR_FILE_NAME "acs.err" + +// TYPES ------------------------------------------------------------------- + +typedef enum +{ + ERRINFO_GCC, + ERRINFO_VCC +} errorInfo_e; + +// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- + +// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- + +// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- + +static char *ErrorText(error_t error); +static char *ErrorFileName(void); +static void eprintf(const char *fmt, ...); +static void veprintf(const char *fmt, va_list args); + +// EXTERNAL DATA DECLARATIONS ---------------------------------------------- + +extern char acs_SourceFileName[MAX_FILE_NAME_LENGTH]; + +// PUBLIC DATA DEFINITIONS ------------------------------------------------- + +// PRIVATE DATA DEFINITIONS ------------------------------------------------ + +static struct +{ + error_t number; + char *name; +} ErrorNames[] = +{ + { ERR_MISSING_SEMICOLON, "Missing semicolon." }, + { ERR_MISSING_LPAREN, "Missing '('." }, + { ERR_MISSING_RPAREN, "Missing ')'." }, + { ERR_MISSING_LBRACE, "Missing '{'." }, + { ERR_MISSING_SCRIPT_NUMBER, "Missing script number." }, + { ERR_IDENTIFIER_TOO_LONG, "Identifier too long." }, + { ERR_STRING_TOO_LONG, "String too long." }, + { ERR_FILE_NAME_TOO_LONG, "File name too long.\nFile: \"%s\"" }, + { ERR_BAD_CHARACTER, "Bad character in script text." }, + { ERR_BAD_CHARACTER_CONSTANT, "Bad character constant in script text." }, + { ERR_ALLOC_PCODE_BUFFER, "Failed to allocate PCODE buffer." }, + { ERR_PCODE_BUFFER_OVERFLOW, "PCODE buffer overflow." }, + { ERR_TOO_MANY_SCRIPTS, "Too many scripts." }, + { ERR_TOO_MANY_FUNCTIONS, "Too many functions." }, + { ERR_SAVE_OBJECT_FAILED, "Couldn't save object file." }, + { ERR_MISSING_LPAREN_SCR, "Missing '(' in script definition." }, + { ERR_INVALID_IDENTIFIER, "Invalid identifier." }, + { ERR_REDEFINED_IDENTIFIER, "%s : Redefined identifier." }, + { ERR_MISSING_COMMA, "Missing comma." }, + { ERR_BAD_VAR_TYPE, "Invalid variable type." }, + { ERR_BAD_RETURN_TYPE, "Invalid return type." }, + { ERR_TOO_MANY_SCRIPT_ARGS, "Too many script arguments." }, + { ERR_MISSING_LBRACE_SCR, "Missing opening '{' in script definition." }, + { ERR_MISSING_RBRACE_SCR, "Missing closing '}' in script definition." }, + { ERR_TOO_MANY_MAP_VARS, "Too many map variables." }, + { ERR_TOO_MANY_SCRIPT_VARS, "Too many script variables." }, + { ERR_TOO_MANY_FUNCTION_VARS, "Too many function variables." }, + { ERR_TOO_MANY_SCRIPT_ARRAYS, "Too many script arrays." }, + { ERR_TOO_MANY_FUNCTION_ARRAYS, "Too many function arrays." }, + { ERR_MISSING_WVAR_INDEX, "Missing index in world variable declaration." }, + { ERR_MISSING_GVAR_INDEX, "Missing index in global variable declaration." }, + { ERR_BAD_WVAR_INDEX, "World variable index out of range." }, + { ERR_MISSING_WVAR_COLON, "Missing colon in world variable declaration." }, + { ERR_MISSING_GVAR_COLON, "Missing colon in global variable declaration." }, + { ERR_MISSING_SPEC_VAL, "Missing value in special declaration." }, + { ERR_MISSING_SPEC_COLON, "Missing colon in special declaration." }, + { ERR_MISSING_SPEC_ARGC, "Missing argument count in special declaration." }, + { ERR_CANT_READ_FILE, "Couldn't read file.\nFile: \"%s\"" }, + { ERR_CANT_OPEN_FILE, "Couldn't open file.\nFile: \"%s\"" }, + { ERR_CANT_OPEN_DBGFILE, "Couldn't open debug file." }, + { ERR_INVALID_DIRECTIVE, "Invalid directive." }, + { ERR_BAD_DEFINE, "Non-numeric constant found in #define." }, + { ERR_INCL_NESTING_TOO_DEEP, "Include nesting too deep.\nUnable to include file \"%s\"." }, + { ERR_STRING_LIT_NOT_FOUND, "String literal not found." }, + { ERR_INVALID_DECLARATOR, "Invalid declarator." }, + { ERR_BAD_LSPEC_ARG_COUNT, "Incorrect number of special arguments." }, + { ERR_BAD_ARG_COUNT, "Incorrect number of arguments." }, + { ERR_UNKNOWN_IDENTIFIER, "%s : Identifier has not been declared." }, + { ERR_MISSING_COLON, "Missing colon." }, + { ERR_BAD_EXPR, "Syntax error in expression." }, + { ERR_BAD_CONST_EXPR, "Syntax error in constant expression." }, + { ERR_DIV_BY_ZERO_IN_CONST_EXPR, "Division by zero in constant expression." }, + { ERR_NO_DIRECT_VER, "Internal function has no direct version." }, + { ERR_ILLEGAL_EXPR_IDENT, "%s : Illegal identifier in expression." }, + { ERR_EXPR_FUNC_NO_RET_VAL, "Function call in expression has no return value." }, + { ERR_MISSING_ASSIGN_OP, "Missing assignment operator." }, + { ERR_INCDEC_OP_ON_NON_VAR, "'++' or '--' used on a non-variable." }, + { ERR_MISSING_RBRACE, "Missing '}' at end of compound statement." }, + { ERR_INVALID_STATEMENT, "Invalid statement." }, + { ERR_BAD_DO_STATEMENT, "Do statement not followed by 'while' or 'until'." }, + { ERR_BAD_SCRIPT_DECL, "Bad script declaration." }, + { ERR_CASE_OVERFLOW, "Internal Error: Case stack overflow." }, + { ERR_BREAK_OVERFLOW, "Internal Error: Break stack overflow." }, + { ERR_CONTINUE_OVERFLOW, "Internal Error: Continue stack overflow." }, + { ERR_STATEMENT_OVERFLOW, "Internal Error: Statement overflow." }, + { ERR_MISPLACED_BREAK, "Misplaced BREAK statement." }, + { ERR_MISPLACED_CONTINUE, "Misplaced CONTINUE statement." }, + { ERR_CASE_NOT_IN_SWITCH, "CASE must appear in switch statement." }, + { ERR_DEFAULT_NOT_IN_SWITCH, "DEFAULT must appear in switch statement." }, + { ERR_MULTIPLE_DEFAULT, "Only 1 DEFAULT per switch allowed." }, + { ERR_EXPR_STACK_OVERFLOW, "Expression stack overflow." }, + { ERR_EXPR_STACK_EMPTY, "Tried to POP empty expression stack." }, + { ERR_UNKNOWN_CONST_EXPR_PCD, "Unknown PCD in constant expression." }, + { ERR_BAD_RADIX_CONSTANT, "Radix out of range in integer constant." }, + { ERR_BAD_ASSIGNMENT, "Syntax error in multiple assignment statement." }, + { ERR_OUT_OF_MEMORY, "Out of memory." }, + { ERR_TOO_MANY_STRINGS, "Too many strings. Current max is %d" }, + { ERR_UNKNOWN_PRTYPE, "Unknown cast type in print statement." }, + { ERR_SCRIPT_OUT_OF_RANGE, "Script number must be between 1 and 32767." }, + { ERR_MISSING_PARAM, "Missing required argument." }, + { ERR_SCRIPT_ALREADY_DEFINED, "Script already has a body." }, + { ERR_FUNCTION_ALREADY_DEFINED, "Function already has a body." }, + { ERR_PARM_MUST_BE_VAR, "Parameter must be a variable." }, + { ERR_MISSING_FONT_NAME, "Missing font name." }, + { ERR_MISSING_LBRACE_FONTS, "Missing opening '{' in font list." }, + { ERR_MISSING_RBRACE_FONTS, "Missing closing '}' in font list." }, + { ERR_NOCOMPACT_NOT_HERE, "#nocompact must appear before any scripts." }, + { ERR_MISSING_ASSIGN, "Missing '='." }, + { ERR_PREVIOUS_NOT_VOID, "Previous use of function expected a return value." }, + { ERR_MUST_RETURN_A_VALUE, "Function must return a value." }, + { ERR_MUST_NOT_RETURN_A_VALUE, "Void functions cannot return a value." }, + { ERR_SUSPEND_IN_FUNCTION, "Suspend cannot be used inside a function." }, + { ERR_TERMINATE_IN_FUNCTION, "Terminate cannot be used inside a function." }, + { ERR_RESTART_IN_FUNCTION, "Restart cannot be used inside a function." }, + { ERR_RETURN_OUTSIDE_FUNCTION, "Return can only be used inside a function." }, + { ERR_FUNC_ARGUMENT_COUNT, "Function %s should have %d argument%s." }, + { ERR_EOF, "Unexpected end of file." }, + { ERR_UNDEFINED_FUNC, "Function %s is used but not defined." }, + { ERR_TOO_MANY_ARRAY_DIMS, "Too many array dimensions." }, + { ERR_TOO_MANY_ARRAY_INIT, "Too many initializers for array." }, + { ERR_MISSING_LBRACKET, "Missing '['." }, + { ERR_MISSING_RBRACKET, "Missing ']'." }, + { ERR_ZERO_DIMENSION, "Arrays cannot have a dimension of zero." }, + { ERR_TOO_MANY_DIM_USED, "%s only has %d dimensions." }, + { ERR_TOO_FEW_DIM_USED, "%s access needs %d more dimensions." }, + { ERR_ARRAY_MAPVAR_ONLY, "Only map variables can be arrays." }, + { ERR_NOT_AN_ARRAY, "%s is not an array." }, + { ERR_MISSING_LBRACE_ARR, "Missing opening '{' in array initializer." }, + { ERR_MISSING_RBRACE_ARR, "Missing closing '}' in array initializer." }, + { ERR_LATENT_IN_FUNC, "Latent functions cannot be used inside functions." }, + { ERR_LOCAL_VAR_SHADOWED, "A global identifier already has this name." }, + { ERR_MULTIPLE_IMPORTS, "You can only #import one file." }, + { ERR_IMPORT_IN_EXPORT, "You cannot #import from inside an imported file." }, + { ERR_EXPORTER_NOT_FLAGGED, "A file that you #import must have a #library line." }, + { ERR_TOO_MANY_IMPORTS, "Too many files imported." }, + { ERR_NO_NEED_ARRAY_SIZE, "Only map arrays need a size." }, + { ERR_NO_MULTIDIMENSIONS, "Only map arrays can have more than one dimension." }, + { ERR_NEED_ARRAY_SIZE, "Missing array size." }, + { ERR_DISCONNECT_NEEDS_1_ARG, "Disconnect scripts must have 1 argument." }, + { ERR_UNCLOSED_WITH_ARGS, "Most special scripts must not have arguments." }, + { ERR_NOT_A_CHAR_ARRAY, "%s has %d dimensions. Use %d subscripts to get a char array." }, + { ERR_CANT_FIND_INCLUDE, "Couldn't find include file \"%s\"." }, + { ERR_SCRIPT_NAMED_NONE, "Scripts may not be named \"None\"." }, + { ERR_HEXEN_COMPAT, "Attempt to use feature not supported by Hexen." }, + { ERR_NOT_HEXEN, "Cannot save; new features are not compatible with Hexen." }, + { ERR_SPECIAL_RANGE, "Line specials with values higher than 255 require #nocompact." }, + { ERR_EVENT_NEEDS_3_ARG, "Event scripts must have 3 arguments." }, // [BB] + { ERR_LIBRARY_NOT_FIRST, "#library must come before anything else." }, + { ERR_NONE, NULL } +}; + +static FILE *ErrorFile; +static int ErrorCount; +static errorInfo_e ErrorFormat; +static char *ErrorSourceName; +static int ErrorSourceLine; + +// CODE -------------------------------------------------------------------- + +//========================================================================== +// +// ERR_ErrorAt +// +//========================================================================== + +void ERR_ErrorAt(char *source, int line) +{ + ErrorSourceName = source; + ErrorSourceLine = line; +} + +//========================================================================== +// +// ERR_Error +// +//========================================================================== + +void ERR_Error(error_t error, boolean info, ...) +{ + va_list args; + va_start(args, info); + ERR_ErrorV(error, info, args); + va_end(args); +} + +//========================================================================== +// +// ERR_Exit +// +//========================================================================== + +void ERR_Exit(error_t error, boolean info, ...) +{ + va_list args; + va_start(args, info); + ERR_ErrorV(error, info, args); + va_end(args); + ERR_Finish(); +} + +//========================================================================== +// +// ERR_Finish +// +//========================================================================== + +void ERR_Finish(void) +{ + if(ErrorFile) + { + fclose(ErrorFile); + ErrorFile = NULL; + } + if(ErrorCount) + { + exit(1); + } +} + +//========================================================================== +// +// ShowError +// +//========================================================================== + +void ERR_ErrorV(error_t error, boolean info, va_list args) +{ + char *text; + boolean showLine = NO; + static boolean showedInfo = NO; + + if(!ErrorFile) + { + ErrorFile = fopen(ErrorFileName(), "w"); + } + if(ErrorCount == 0) + { + fprintf(stderr, "\n**** ERROR ****\n"); + } + else if(ErrorCount == 100) + { + eprintf("More than 100 errors. Can't continue.\n"); + ERR_Finish(); + } + ErrorCount++; + if(info == YES) + { + char *source; + int line; + + if(ErrorSourceName) + { + source = ErrorSourceName; + line = ErrorSourceLine; + ErrorSourceName = NULL; + } + else + { + source = tk_SourceName; + line = tk_Line; + showLine = YES; + } + if(showedInfo == NO) + { // Output info compatible with older ACCs + // for editors that expect it. + showedInfo = YES; + eprintf("Line %d in file \"%s\" ...\n", line, source); + } + if(ErrorFormat == ERRINFO_GCC) + { + eprintf("%s:%d: ", source, line); + } + else + { + eprintf("%s(%d) : ", source, line); + if(error != ERR_NONE) + { + eprintf("error %04d: ", error); + } + } + } + if(error != ERR_NONE) + { + text = ErrorText(error); + if(text != NULL) + { + veprintf(text, args); + } + eprintf("\n"); + if(showLine) + { + // deal with master source line and position indicator - Ty 07jan2000 + MasterSourceLine[MasterSourcePos] = '\0'; // pre-incremented already + eprintf("> %s\n", MasterSourceLine); // the string + eprintf(">%*s\n", MasterSourcePos, "^"); // pointer to error + } + } +#if 0 + else + { + va_list args2; + va_start(va_arg(args,char*), args2); + veprintf(va_arg(args,char*), args2); + va_end(args2); + } +#endif +} + +//========================================================================== +// +// ERR_RemoveErrorFile +// +//========================================================================== + +void ERR_RemoveErrorFile(void) +{ + remove(ErrorFileName()); +} + +//========================================================================== +// +// ERR_ErrorFileName +// +//========================================================================== + +static char *ErrorFileName(void) +{ + static char errFileName[MAX_FILE_NAME_LENGTH]; + + strcpy(errFileName, acs_SourceFileName); + if(MS_StripFilename(errFileName) == NO) + { + strcpy(errFileName, ERROR_FILE_NAME); + } + else + { + strcat(errFileName, ERROR_FILE_NAME); + } + return errFileName; +} + +//========================================================================== +// +// ErrorText +// +//========================================================================== + +static char *ErrorText(error_t error) +{ + int i; + + for(i = 0; ErrorNames[i].number != ERR_NONE; i++) + { + if(error == ErrorNames[i].number) + { + return ErrorNames[i].name; + } + } + return NULL; +} + +//========================================================================== +// +// eprintf +// +//========================================================================== + +static void eprintf(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + veprintf(fmt, args); + va_end(args); +} + +//========================================================================== +// +// veprintf +// +//========================================================================== + +static void veprintf(const char *fmt, va_list args) +{ +#ifdef va_copy + va_list copy; + va_copy(copy, args); +#endif + vfprintf(stderr, fmt, args); + if(ErrorFile) + { +#ifdef va_copy + vfprintf(ErrorFile, fmt, copy); +#else + vfprintf(ErrorFile, fmt, args); +#endif + } +#ifdef va_copy + va_end(copy); +#endif +} diff --git a/error.h b/error.h index a6c36b5..d7e696b 100644 --- a/error.h +++ b/error.h @@ -1,165 +1,165 @@ - -//************************************************************************** -//** -//** error.h -//** -//************************************************************************** - -#ifndef __ERROR_H__ -#define __ERROR_H__ - -// HEADER FILES ------------------------------------------------------------ - -#include -#include "common.h" - -// MACROS ------------------------------------------------------------------ - -// TYPES ------------------------------------------------------------------- - -typedef enum -{ - ERR_NONE = 0, - ERR_NO_SYMBOL_MEM = 10, - ERR_IDENTIFIER_TOO_LONG, - ERR_STRING_TOO_LONG, - ERR_FILE_NAME_TOO_LONG, - ERR_MISSING_LPAREN, - ERR_MISSING_RPAREN, - ERR_MISSING_SEMICOLON, - ERR_MISSING_SCRIPT_NUMBER, - ERR_ALLOC_PCODE_BUFFER, - ERR_PCODE_BUFFER_OVERFLOW, - ERR_TOO_MANY_SCRIPTS, - ERR_TOO_MANY_FUNCTIONS, - ERR_SAVE_OBJECT_FAILED, - ERR_MISSING_LPAREN_SCR, - ERR_INVALID_IDENTIFIER, - ERR_REDEFINED_IDENTIFIER, - ERR_MISSING_COMMA, - ERR_BAD_VAR_TYPE, - ERR_BAD_RETURN_TYPE, - ERR_TOO_MANY_SCRIPT_ARGS, - ERR_MISSING_LBRACE_SCR, - ERR_MISSING_RBRACE_SCR, - ERR_TOO_MANY_MAP_VARS, - ERR_MISSING_WVAR_INDEX, - ERR_MISSING_GVAR_INDEX, - ERR_BAD_WVAR_INDEX, - ERR_MISSING_WVAR_COLON, - ERR_MISSING_GVAR_COLON, - ERR_MISSING_SPEC_VAL, - ERR_MISSING_SPEC_COLON, - ERR_MISSING_SPEC_ARGC, - ERR_CANT_READ_FILE, - ERR_CANT_OPEN_FILE, - ERR_CANT_OPEN_DBGFILE, - ERR_INVALID_DIRECTIVE, - ERR_BAD_DEFINE, - ERR_INCL_NESTING_TOO_DEEP, - ERR_STRING_LIT_NOT_FOUND, - ERR_TOO_MANY_SCRIPT_VARS, - ERR_TOO_MANY_FUNCTION_VARS, - ERR_TOO_MANY_SCRIPT_ARRAYS, - ERR_TOO_MANY_FUNCTION_ARRAYS, - ERR_INVALID_DECLARATOR, - ERR_BAD_LSPEC_ARG_COUNT, - ERR_BAD_ARG_COUNT, - ERR_UNKNOWN_IDENTIFIER, - ERR_MISSING_COLON, - ERR_BAD_EXPR, - ERR_BAD_CONST_EXPR, - ERR_DIV_BY_ZERO_IN_CONST_EXPR, - ERR_NO_DIRECT_VER, - ERR_ILLEGAL_EXPR_IDENT, - ERR_EXPR_FUNC_NO_RET_VAL, - ERR_MISSING_ASSIGN_OP, - ERR_INCDEC_OP_ON_NON_VAR, - ERR_MISSING_RBRACE, - ERR_INVALID_STATEMENT, - ERR_BAD_DO_STATEMENT, - ERR_BAD_SCRIPT_DECL, - ERR_CASE_OVERFLOW, - ERR_BREAK_OVERFLOW, - ERR_CONTINUE_OVERFLOW, - ERR_STATEMENT_OVERFLOW, - ERR_MISPLACED_BREAK, - ERR_MISPLACED_CONTINUE, - ERR_CASE_NOT_IN_SWITCH, - ERR_DEFAULT_NOT_IN_SWITCH, - ERR_MULTIPLE_DEFAULT, - ERR_EXPR_STACK_OVERFLOW, - ERR_EXPR_STACK_EMPTY, - ERR_UNKNOWN_CONST_EXPR_PCD, - ERR_BAD_RADIX_CONSTANT, - ERR_BAD_ASSIGNMENT, - ERR_OUT_OF_MEMORY, - ERR_TOO_MANY_STRINGS, - ERR_UNKNOWN_PRTYPE, - ERR_BAD_CHARACTER, - ERR_SCRIPT_OUT_OF_RANGE, - ERR_MISSING_PARAM, - ERR_SCRIPT_ALREADY_DEFINED, - ERR_FUNCTION_ALREADY_DEFINED, - ERR_PARM_MUST_BE_VAR, - ERR_MISSING_FONT_NAME, - ERR_MISSING_LBRACE_FONTS, - ERR_MISSING_RBRACE_FONTS, - ERR_NOCOMPACT_NOT_HERE, - ERR_MISSING_ASSIGN, - ERR_MUST_RETURN_A_VALUE, - ERR_MUST_NOT_RETURN_A_VALUE, - ERR_SUSPEND_IN_FUNCTION, - ERR_TERMINATE_IN_FUNCTION, - ERR_RESTART_IN_FUNCTION, - ERR_RETURN_OUTSIDE_FUNCTION, - ERR_PREVIOUS_NOT_VOID, - ERR_MISSING_LBRACE, - ERR_FUNC_ARGUMENT_COUNT, - ERR_UNDEFINED_FUNC, - ERR_TOO_MANY_ARRAY_DIMS, - ERR_MISSING_LBRACKET, - ERR_MISSING_RBRACKET, - ERR_ZERO_DIMENSION, - ERR_TOO_MANY_DIM_USED, - ERR_TOO_FEW_DIM_USED, - ERR_TOO_MANY_ARRAY_INIT, - ERR_EOF, - ERR_ARRAY_MAPVAR_ONLY, - ERR_NOT_AN_ARRAY, - ERR_MISSING_LBRACE_ARR, - ERR_MISSING_RBRACE_ARR, - ERR_LATENT_IN_FUNC, - ERR_LOCAL_VAR_SHADOWED, - ERR_BAD_CHARACTER_CONSTANT, - ERR_MULTIPLE_IMPORTS, - ERR_IMPORT_IN_EXPORT, - ERR_EXPORTER_NOT_FLAGGED, - ERR_TOO_MANY_IMPORTS, - ERR_NO_NEED_ARRAY_SIZE, - ERR_NO_MULTIDIMENSIONS, - ERR_NEED_ARRAY_SIZE, - ERR_DISCONNECT_NEEDS_1_ARG, - ERR_UNCLOSED_WITH_ARGS, - ERR_NOT_A_CHAR_ARRAY, - ERR_CANT_FIND_INCLUDE, - ERR_SCRIPT_NAMED_NONE, - ERR_HEXEN_COMPAT, - ERR_NOT_HEXEN, - ERR_SPECIAL_RANGE, - ERR_EVENT_NEEDS_3_ARG, // [BB] - ERR_LIBRARY_NOT_FIRST, -} error_t; - -// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- - -void ERR_ErrorAt(char *sourceName, int sourceLine); -void ERR_Error(error_t error, boolean info, ...); -void ERR_ErrorV(error_t error, boolean info, va_list args); -void ERR_Finish(void); -void ERR_Exit(error_t error, boolean info, ...); -void ERR_RemoveErrorFile(void); - -// PUBLIC DATA DECLARATIONS ------------------------------------------------ - -#endif + +//************************************************************************** +//** +//** error.h +//** +//************************************************************************** + +#ifndef __ERROR_H__ +#define __ERROR_H__ + +// HEADER FILES ------------------------------------------------------------ + +#include +#include "common.h" + +// MACROS ------------------------------------------------------------------ + +// TYPES ------------------------------------------------------------------- + +typedef enum +{ + ERR_NONE = 0, + ERR_NO_SYMBOL_MEM = 10, + ERR_IDENTIFIER_TOO_LONG, + ERR_STRING_TOO_LONG, + ERR_FILE_NAME_TOO_LONG, + ERR_MISSING_LPAREN, + ERR_MISSING_RPAREN, + ERR_MISSING_SEMICOLON, + ERR_MISSING_SCRIPT_NUMBER, + ERR_ALLOC_PCODE_BUFFER, + ERR_PCODE_BUFFER_OVERFLOW, + ERR_TOO_MANY_SCRIPTS, + ERR_TOO_MANY_FUNCTIONS, + ERR_SAVE_OBJECT_FAILED, + ERR_MISSING_LPAREN_SCR, + ERR_INVALID_IDENTIFIER, + ERR_REDEFINED_IDENTIFIER, + ERR_MISSING_COMMA, + ERR_BAD_VAR_TYPE, + ERR_BAD_RETURN_TYPE, + ERR_TOO_MANY_SCRIPT_ARGS, + ERR_MISSING_LBRACE_SCR, + ERR_MISSING_RBRACE_SCR, + ERR_TOO_MANY_MAP_VARS, + ERR_MISSING_WVAR_INDEX, + ERR_MISSING_GVAR_INDEX, + ERR_BAD_WVAR_INDEX, + ERR_MISSING_WVAR_COLON, + ERR_MISSING_GVAR_COLON, + ERR_MISSING_SPEC_VAL, + ERR_MISSING_SPEC_COLON, + ERR_MISSING_SPEC_ARGC, + ERR_CANT_READ_FILE, + ERR_CANT_OPEN_FILE, + ERR_CANT_OPEN_DBGFILE, + ERR_INVALID_DIRECTIVE, + ERR_BAD_DEFINE, + ERR_INCL_NESTING_TOO_DEEP, + ERR_STRING_LIT_NOT_FOUND, + ERR_TOO_MANY_SCRIPT_VARS, + ERR_TOO_MANY_FUNCTION_VARS, + ERR_TOO_MANY_SCRIPT_ARRAYS, + ERR_TOO_MANY_FUNCTION_ARRAYS, + ERR_INVALID_DECLARATOR, + ERR_BAD_LSPEC_ARG_COUNT, + ERR_BAD_ARG_COUNT, + ERR_UNKNOWN_IDENTIFIER, + ERR_MISSING_COLON, + ERR_BAD_EXPR, + ERR_BAD_CONST_EXPR, + ERR_DIV_BY_ZERO_IN_CONST_EXPR, + ERR_NO_DIRECT_VER, + ERR_ILLEGAL_EXPR_IDENT, + ERR_EXPR_FUNC_NO_RET_VAL, + ERR_MISSING_ASSIGN_OP, + ERR_INCDEC_OP_ON_NON_VAR, + ERR_MISSING_RBRACE, + ERR_INVALID_STATEMENT, + ERR_BAD_DO_STATEMENT, + ERR_BAD_SCRIPT_DECL, + ERR_CASE_OVERFLOW, + ERR_BREAK_OVERFLOW, + ERR_CONTINUE_OVERFLOW, + ERR_STATEMENT_OVERFLOW, + ERR_MISPLACED_BREAK, + ERR_MISPLACED_CONTINUE, + ERR_CASE_NOT_IN_SWITCH, + ERR_DEFAULT_NOT_IN_SWITCH, + ERR_MULTIPLE_DEFAULT, + ERR_EXPR_STACK_OVERFLOW, + ERR_EXPR_STACK_EMPTY, + ERR_UNKNOWN_CONST_EXPR_PCD, + ERR_BAD_RADIX_CONSTANT, + ERR_BAD_ASSIGNMENT, + ERR_OUT_OF_MEMORY, + ERR_TOO_MANY_STRINGS, + ERR_UNKNOWN_PRTYPE, + ERR_BAD_CHARACTER, + ERR_SCRIPT_OUT_OF_RANGE, + ERR_MISSING_PARAM, + ERR_SCRIPT_ALREADY_DEFINED, + ERR_FUNCTION_ALREADY_DEFINED, + ERR_PARM_MUST_BE_VAR, + ERR_MISSING_FONT_NAME, + ERR_MISSING_LBRACE_FONTS, + ERR_MISSING_RBRACE_FONTS, + ERR_NOCOMPACT_NOT_HERE, + ERR_MISSING_ASSIGN, + ERR_MUST_RETURN_A_VALUE, + ERR_MUST_NOT_RETURN_A_VALUE, + ERR_SUSPEND_IN_FUNCTION, + ERR_TERMINATE_IN_FUNCTION, + ERR_RESTART_IN_FUNCTION, + ERR_RETURN_OUTSIDE_FUNCTION, + ERR_PREVIOUS_NOT_VOID, + ERR_MISSING_LBRACE, + ERR_FUNC_ARGUMENT_COUNT, + ERR_UNDEFINED_FUNC, + ERR_TOO_MANY_ARRAY_DIMS, + ERR_MISSING_LBRACKET, + ERR_MISSING_RBRACKET, + ERR_ZERO_DIMENSION, + ERR_TOO_MANY_DIM_USED, + ERR_TOO_FEW_DIM_USED, + ERR_TOO_MANY_ARRAY_INIT, + ERR_EOF, + ERR_ARRAY_MAPVAR_ONLY, + ERR_NOT_AN_ARRAY, + ERR_MISSING_LBRACE_ARR, + ERR_MISSING_RBRACE_ARR, + ERR_LATENT_IN_FUNC, + ERR_LOCAL_VAR_SHADOWED, + ERR_BAD_CHARACTER_CONSTANT, + ERR_MULTIPLE_IMPORTS, + ERR_IMPORT_IN_EXPORT, + ERR_EXPORTER_NOT_FLAGGED, + ERR_TOO_MANY_IMPORTS, + ERR_NO_NEED_ARRAY_SIZE, + ERR_NO_MULTIDIMENSIONS, + ERR_NEED_ARRAY_SIZE, + ERR_DISCONNECT_NEEDS_1_ARG, + ERR_UNCLOSED_WITH_ARGS, + ERR_NOT_A_CHAR_ARRAY, + ERR_CANT_FIND_INCLUDE, + ERR_SCRIPT_NAMED_NONE, + ERR_HEXEN_COMPAT, + ERR_NOT_HEXEN, + ERR_SPECIAL_RANGE, + ERR_EVENT_NEEDS_3_ARG, // [BB] + ERR_LIBRARY_NOT_FIRST, +} error_t; + +// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- + +void ERR_ErrorAt(char *sourceName, int sourceLine); +void ERR_Error(error_t error, boolean info, ...); +void ERR_ErrorV(error_t error, boolean info, va_list args); +void ERR_Finish(void); +void ERR_Exit(error_t error, boolean info, ...); +void ERR_RemoveErrorFile(void); + +// PUBLIC DATA DECLARATIONS ------------------------------------------------ + +#endif diff --git a/misc.c b/misc.c index 7bdf7ad..a97eb43 100644 --- a/misc.c +++ b/misc.c @@ -1,408 +1,408 @@ - -//************************************************************************** -//** -//** misc.c -//** -//************************************************************************** - -// HEADER FILES ------------------------------------------------------------ - -#ifdef __NeXT__ -#include -#else -#include -#include -#if !defined(unix) && !defined(__APPLE__) -#include -#endif -#endif -#ifdef __GNUC__ -#include -#include -#endif -#ifdef _WIN32 -#include -#include -#endif -#include -#include -#include -#include -#include -#include "common.h" -#include "misc.h" -#include "error.h" - -// MACROS ------------------------------------------------------------------ - -#ifndef O_BINARY -#define O_BINARY 0 -#endif - -// TYPES ------------------------------------------------------------------- - -// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- - -// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- - -// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- - -// EXTERNAL DATA DECLARATIONS ---------------------------------------------- - -extern boolean acs_BigEndianHost; -extern boolean acs_VerboseMode; -extern boolean acs_DebugMode; -extern FILE *acs_DebugFile; - -// PUBLIC DATA DEFINITIONS ------------------------------------------------- - -// PRIVATE DATA DEFINITIONS ------------------------------------------------ - -// CODE -------------------------------------------------------------------- - -//========================================================================== -// -// MS_Alloc -// -//========================================================================== - -void *MS_Alloc(size_t size, error_t error) -{ - void *mem; - - if((mem = malloc(size)) == NULL) - { - ERR_Exit(error, NO); - } - return mem; -} - -//========================================================================== -// -// MS_Realloc -// -//========================================================================== - -void *MS_Realloc(void *base, size_t size, error_t error) -{ - void *mem; - - if((mem = realloc(base, size)) == NULL) - { - ERR_Exit(error, NO); - } - return mem; -} - -//========================================================================== -// -// MS_LittleUWORD -// -// Converts a host U_WORD (2 bytes) to little endian byte order. -// -//========================================================================== - -U_WORD MS_LittleUWORD(U_WORD val) -{ - if(acs_BigEndianHost == NO) - { - return val; - } - return ((val&255)<<8)+((val>>8)&255); -} - -//========================================================================== -// -// MS_LittleUINT -// -// Converts a host U_INT (4 bytes) to little endian byte order. -// -//========================================================================== - -U_INT MS_LittleUINT(U_INT val) -{ - if(acs_BigEndianHost == NO) - { - return val; - } - return ((val&255)<<24)+(((val>>8)&255)<<16)+(((val>>16)&255)<<8) - +((val>>24)&255); -} - -//========================================================================== -// -// MS_LoadFile -// -//========================================================================== - -int MS_LoadFile(char *name, char **buffer) -{ - int handle; - int size; - int count; - char *addr; - struct stat fileInfo; - - if(strlen(name) >= MAX_FILE_NAME_LENGTH) - { - ERR_Exit(ERR_FILE_NAME_TOO_LONG, NO, name); - } - if((handle = open(name, O_RDONLY|O_BINARY, 0666)) == -1) - { - ERR_Exit(ERR_CANT_OPEN_FILE, NO, name); - } - if(fstat(handle, &fileInfo) == -1) - { - ERR_Exit(ERR_CANT_READ_FILE, NO, name); - } - size = fileInfo.st_size; - if((addr = malloc(size)) == NULL) - { - ERR_Exit(ERR_NONE, NO, "Couldn't malloc %d bytes for " - "file \"%s\".", size, name); - } - count = read(handle, addr, size); - close(handle); - if(count < size) - { - ERR_Exit(ERR_CANT_READ_FILE, NO, name); - } - *buffer = addr; - return size; -} - - -//========================================================================== -// -// MS_FileExists -// -// Pascal 21/11/08 -// -//========================================================================== -boolean MS_FileExists(char *name) -{ - struct stat info; - int ret = stat(name, &info); - return (ret == 0); -} - - -//========================================================================== -// -// MS_SaveFile -// -//========================================================================== - -boolean MS_SaveFile(char *name, void *buffer, int length) -{ - int handle; - int count; - - handle = open(name, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0666); - if(handle == -1) - { - return FALSE; - } - count = write(handle, buffer, length); - close(handle); - if(count < length) - { - return FALSE; - } - return TRUE; -} - -//========================================================================== -// -// MS_StrCmp -// -//========================================================================== - -int MS_StrCmp(char *s1, char *s2) -{ - for(; tolower(*s1) == tolower(*s2); s1++, s2++) - { - if(*s1 == '\0') - { - return 0; - } - } - return tolower(*s1)-tolower(*s2); -} - -//========================================================================== -// -// MS_StrLwr -// -//========================================================================== - -char *MS_StrLwr(char *string) -{ - char *c; - - c = string; - while(*c) - { - *c = tolower(*c); - c++; - } - return string; -} - -//========================================================================== -// -// MS_StrUpr -// -//========================================================================== - -char *MS_StrUpr(char *string) -{ - char *c; - - c = string; - while(*c) - { - *c = toupper(*c); - c++; - } - return string; -} - -//========================================================================== -// -// MS_SuggestFileExt -// -//========================================================================== - -void MS_SuggestFileExt(char *base, char *extension) -{ - char *search; - - search = base+strlen(base)-1; - while(!MS_IsDirectoryDelimiter(*search) && search != base) - { - if(*search-- == '.') - { - return; - } - } - strcat(base, extension); -} - -//========================================================================== -// -// MS_IsDirectoryDelimiter -// -//========================================================================== - -boolean MS_IsDirectoryDelimiter(char foo) -{ -#if defined(_WIN32) || defined(__MSDOS__) - return foo == '/' || foo == '\\' || foo == ':'; -#else - return foo == '/'; -#endif -} - - -//========================================================================== -// -// MS_StripFileExt -// -//========================================================================== - -void MS_StripFileExt(char *name) -{ - char *search; - - search = name+strlen(name)-1; - while(!MS_IsDirectoryDelimiter(*search) && search != name) - { - if(*search == '.') - { - *search = '\0'; - return; - } - search--; - } -} - -//========================================================================== -// -// MS_StripFilename -// -// [RH] This now leaves the directory delimiter in place. -// -//========================================================================== - -boolean MS_StripFilename(char *name) -{ - char *c; - - c = name+strlen(name); - do - { - if(--c == name) - { // No directory delimiter - return NO; - } - } while(!MS_IsDirectoryDelimiter(*c)); - *(c+1) = 0; - return YES; -} - -//========================================================================== -// -// MS_Message -// -//========================================================================== - -void MS_Message(msg_t type, char *text, ...) -{ - FILE *fp; - va_list argPtr; - - if(type == MSG_VERBOSE && acs_VerboseMode == NO) - { - return; - } - fp = stdout; - if(type == MSG_DEBUG) - { - if(acs_DebugMode == NO) - { - return; - } - if(acs_DebugFile != NULL) - { - fp = acs_DebugFile; - } - } - if(text) - { - va_start(argPtr, text); - vfprintf(fp, text, argPtr); - va_end(argPtr); - } -} - -//========================================================================== -// -// MS_IsPathAbsolute -// -// Pascal 30/11/08 -// -//========================================================================== - -boolean MS_IsPathAbsolute(char *name) -{ -#if defined(_WIN32) || defined(__MSDOS__) - // In Windows, the second character must be : if it is an - // absolute path (the first character indicates the drive) - // or the first character is either / or \ for absolute path - if((name[0] != '\0') && (name[1] == ':')) - return TRUE; -#endif - // In Unix-land, the first character must be / for a root path - return MS_IsDirectoryDelimiter(name[0]); -} + +//************************************************************************** +//** +//** misc.c +//** +//************************************************************************** + +// HEADER FILES ------------------------------------------------------------ + +#ifdef __NeXT__ +#include +#else +#include +#include +#if !defined(unix) && !defined(__APPLE__) +#include +#endif +#endif +#ifdef __GNUC__ +#include +#include +#endif +#ifdef _WIN32 +#include +#include +#endif +#include +#include +#include +#include +#include +#include "common.h" +#include "misc.h" +#include "error.h" + +// MACROS ------------------------------------------------------------------ + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +// TYPES ------------------------------------------------------------------- + +// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- + +// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- + +// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- + +// EXTERNAL DATA DECLARATIONS ---------------------------------------------- + +extern boolean acs_BigEndianHost; +extern boolean acs_VerboseMode; +extern boolean acs_DebugMode; +extern FILE *acs_DebugFile; + +// PUBLIC DATA DEFINITIONS ------------------------------------------------- + +// PRIVATE DATA DEFINITIONS ------------------------------------------------ + +// CODE -------------------------------------------------------------------- + +//========================================================================== +// +// MS_Alloc +// +//========================================================================== + +void *MS_Alloc(size_t size, error_t error) +{ + void *mem; + + if((mem = malloc(size)) == NULL) + { + ERR_Exit(error, NO); + } + return mem; +} + +//========================================================================== +// +// MS_Realloc +// +//========================================================================== + +void *MS_Realloc(void *base, size_t size, error_t error) +{ + void *mem; + + if((mem = realloc(base, size)) == NULL) + { + ERR_Exit(error, NO); + } + return mem; +} + +//========================================================================== +// +// MS_LittleUWORD +// +// Converts a host U_WORD (2 bytes) to little endian byte order. +// +//========================================================================== + +U_WORD MS_LittleUWORD(U_WORD val) +{ + if(acs_BigEndianHost == NO) + { + return val; + } + return ((val&255)<<8)+((val>>8)&255); +} + +//========================================================================== +// +// MS_LittleUINT +// +// Converts a host U_INT (4 bytes) to little endian byte order. +// +//========================================================================== + +U_INT MS_LittleUINT(U_INT val) +{ + if(acs_BigEndianHost == NO) + { + return val; + } + return ((val&255)<<24)+(((val>>8)&255)<<16)+(((val>>16)&255)<<8) + +((val>>24)&255); +} + +//========================================================================== +// +// MS_LoadFile +// +//========================================================================== + +int MS_LoadFile(char *name, char **buffer) +{ + int handle; + int size; + int count; + char *addr; + struct stat fileInfo; + + if(strlen(name) >= MAX_FILE_NAME_LENGTH) + { + ERR_Exit(ERR_FILE_NAME_TOO_LONG, NO, name); + } + if((handle = open(name, O_RDONLY|O_BINARY, 0666)) == -1) + { + ERR_Exit(ERR_CANT_OPEN_FILE, NO, name); + } + if(fstat(handle, &fileInfo) == -1) + { + ERR_Exit(ERR_CANT_READ_FILE, NO, name); + } + size = fileInfo.st_size; + if((addr = malloc(size)) == NULL) + { + ERR_Exit(ERR_NONE, NO, "Couldn't malloc %d bytes for " + "file \"%s\".", size, name); + } + count = read(handle, addr, size); + close(handle); + if(count < size) + { + ERR_Exit(ERR_CANT_READ_FILE, NO, name); + } + *buffer = addr; + return size; +} + + +//========================================================================== +// +// MS_FileExists +// +// Pascal 21/11/08 +// +//========================================================================== +boolean MS_FileExists(char *name) +{ + struct stat info; + int ret = stat(name, &info); + return (ret == 0); +} + + +//========================================================================== +// +// MS_SaveFile +// +//========================================================================== + +boolean MS_SaveFile(char *name, void *buffer, int length) +{ + int handle; + int count; + + handle = open(name, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0666); + if(handle == -1) + { + return FALSE; + } + count = write(handle, buffer, length); + close(handle); + if(count < length) + { + return FALSE; + } + return TRUE; +} + +//========================================================================== +// +// MS_StrCmp +// +//========================================================================== + +int MS_StrCmp(char *s1, char *s2) +{ + for(; tolower(*s1) == tolower(*s2); s1++, s2++) + { + if(*s1 == '\0') + { + return 0; + } + } + return tolower(*s1)-tolower(*s2); +} + +//========================================================================== +// +// MS_StrLwr +// +//========================================================================== + +char *MS_StrLwr(char *string) +{ + char *c; + + c = string; + while(*c) + { + *c = tolower(*c); + c++; + } + return string; +} + +//========================================================================== +// +// MS_StrUpr +// +//========================================================================== + +char *MS_StrUpr(char *string) +{ + char *c; + + c = string; + while(*c) + { + *c = toupper(*c); + c++; + } + return string; +} + +//========================================================================== +// +// MS_SuggestFileExt +// +//========================================================================== + +void MS_SuggestFileExt(char *base, char *extension) +{ + char *search; + + search = base+strlen(base)-1; + while(!MS_IsDirectoryDelimiter(*search) && search != base) + { + if(*search-- == '.') + { + return; + } + } + strcat(base, extension); +} + +//========================================================================== +// +// MS_IsDirectoryDelimiter +// +//========================================================================== + +boolean MS_IsDirectoryDelimiter(char foo) +{ +#if defined(_WIN32) || defined(__MSDOS__) + return foo == '/' || foo == '\\' || foo == ':'; +#else + return foo == '/'; +#endif +} + + +//========================================================================== +// +// MS_StripFileExt +// +//========================================================================== + +void MS_StripFileExt(char *name) +{ + char *search; + + search = name+strlen(name)-1; + while(!MS_IsDirectoryDelimiter(*search) && search != name) + { + if(*search == '.') + { + *search = '\0'; + return; + } + search--; + } +} + +//========================================================================== +// +// MS_StripFilename +// +// [RH] This now leaves the directory delimiter in place. +// +//========================================================================== + +boolean MS_StripFilename(char *name) +{ + char *c; + + c = name+strlen(name); + do + { + if(--c == name) + { // No directory delimiter + return NO; + } + } while(!MS_IsDirectoryDelimiter(*c)); + *(c+1) = 0; + return YES; +} + +//========================================================================== +// +// MS_Message +// +//========================================================================== + +void MS_Message(msg_t type, char *text, ...) +{ + FILE *fp; + va_list argPtr; + + if(type == MSG_VERBOSE && acs_VerboseMode == NO) + { + return; + } + fp = stdout; + if(type == MSG_DEBUG) + { + if(acs_DebugMode == NO) + { + return; + } + if(acs_DebugFile != NULL) + { + fp = acs_DebugFile; + } + } + if(text) + { + va_start(argPtr, text); + vfprintf(fp, text, argPtr); + va_end(argPtr); + } +} + +//========================================================================== +// +// MS_IsPathAbsolute +// +// Pascal 30/11/08 +// +//========================================================================== + +boolean MS_IsPathAbsolute(char *name) +{ +#if defined(_WIN32) || defined(__MSDOS__) + // In Windows, the second character must be : if it is an + // absolute path (the first character indicates the drive) + // or the first character is either / or \ for absolute path + if((name[0] != '\0') && (name[1] == ':')) + return TRUE; +#endif + // In Unix-land, the first character must be / for a root path + return MS_IsDirectoryDelimiter(name[0]); +} diff --git a/misc.h b/misc.h index 2c54035..0ded737 100644 --- a/misc.h +++ b/misc.h @@ -1,58 +1,58 @@ - -//************************************************************************** -//** -//** misc.h -//** -//************************************************************************** - -#ifndef __MISC_H__ -#define __MISC_H__ - -// HEADER FILES ------------------------------------------------------------ - -#include -#include "error.h" - -// MACROS ------------------------------------------------------------------ - -#ifdef _WIN32 -#define strcasecmp stricmp -#endif - -// TYPES ------------------------------------------------------------------- - -typedef enum -{ - MSG_NORMAL, - MSG_VERBOSE, - MSG_DEBUG -} msg_t; - -// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- - -void *MS_Alloc(size_t size, error_t error); -void *MS_Realloc(void *base, size_t size, error_t error); -U_WORD MS_LittleUWORD(U_WORD val); -// U_LONG MS_LittleULONG(U_LONG val); -U_INT MS_LittleUINT(U_INT val); -int MS_LoadFile(char *name, char **buffer); -boolean MS_FileExists(char *name); -boolean MS_SaveFile(char *name, void *buffer, int length); -int MS_StrCmp(char *s1, char *s2); -char *MS_StrLwr(char *string); -char *MS_StrUpr(char *string); -void MS_SuggestFileExt(char *base, char *extension); -void MS_StripFileExt(char *name); -boolean MS_StripFilename(char *path); -void MS_Message(msg_t type, char *text, ...); -boolean MS_IsPathAbsolute(char *name); -boolean MS_IsDirectoryDelimiter(char test); - -// PUBLIC DATA DECLARATIONS ------------------------------------------------ - -#ifdef _MSC_VER -// Get rid of the annoying deprecation warnings with VC++2005 and newer. -#pragma warning(disable:4996) -#endif - -#endif + +//************************************************************************** +//** +//** misc.h +//** +//************************************************************************** + +#ifndef __MISC_H__ +#define __MISC_H__ + +// HEADER FILES ------------------------------------------------------------ + +#include +#include "error.h" + +// MACROS ------------------------------------------------------------------ + +#ifdef _WIN32 +#define strcasecmp stricmp +#endif + +// TYPES ------------------------------------------------------------------- + +typedef enum +{ + MSG_NORMAL, + MSG_VERBOSE, + MSG_DEBUG +} msg_t; + +// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- + +void *MS_Alloc(size_t size, error_t error); +void *MS_Realloc(void *base, size_t size, error_t error); +U_WORD MS_LittleUWORD(U_WORD val); +// U_LONG MS_LittleULONG(U_LONG val); +U_INT MS_LittleUINT(U_INT val); +int MS_LoadFile(char *name, char **buffer); +boolean MS_FileExists(char *name); +boolean MS_SaveFile(char *name, void *buffer, int length); +int MS_StrCmp(char *s1, char *s2); +char *MS_StrLwr(char *string); +char *MS_StrUpr(char *string); +void MS_SuggestFileExt(char *base, char *extension); +void MS_StripFileExt(char *name); +boolean MS_StripFilename(char *path); +void MS_Message(msg_t type, char *text, ...); +boolean MS_IsPathAbsolute(char *name); +boolean MS_IsDirectoryDelimiter(char test); + +// PUBLIC DATA DECLARATIONS ------------------------------------------------ + +#ifdef _MSC_VER +// Get rid of the annoying deprecation warnings with VC++2005 and newer. +#pragma warning(disable:4996) +#endif + +#endif diff --git a/parse.c b/parse.c index 6fffcae..52a0fa3 100644 --- a/parse.c +++ b/parse.c @@ -1,4845 +1,4845 @@ - -//************************************************************************** -//** -//** parse.c -//** -//************************************************************************** - -// HEADER FILES ------------------------------------------------------------ - -#include -#include -#include -#include -#include - -#include "common.h" -#include "parse.h" -#include "symbol.h" -#include "pcode.h" -#include "token.h" -#include "error.h" -#include "misc.h" -#include "strlist.h" - -// MACROS ------------------------------------------------------------------ - -#define MAX_STATEMENT_DEPTH 128 -#define MAX_BREAK 128 -#define MAX_CONTINUE 128 -#define MAX_CASE 128 -#define EXPR_STACK_DEPTH 64 - -// TYPES ------------------------------------------------------------------- - -typedef enum -{ - STMT_SCRIPT, - STMT_IF, - STMT_ELSE, - STMT_DO, - STMT_WHILEUNTIL, - STMT_SWITCH, - STMT_FOR -} statement_t; - -typedef struct -{ - int level; - int addressPtr; -} breakInfo_t; - -typedef struct -{ - int level; - int addressPtr; -} continueInfo_t; - -typedef struct -{ - int level; - int value; - boolean isDefault; - int address; -} caseInfo_t; - -typedef struct prefunc_s -{ - struct prefunc_s *next; - symbolNode_t *sym; - int address; - int argcount; - int line; - char *source; -} prefunc_t; - -// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- - -// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- - -// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- - -static void CountScript(int type); -static void Outside(void); -static void OuterScript(void); -static void OuterFunction(void); -static void OuterMapVar(boolean local); -static void OuterWorldVar(boolean isGlobal); -static void OuterSpecialDef(void); -static void OuterDefine(boolean force); -static void OuterInclude(void); -static void OuterImport(void); -static boolean ProcessStatement(statement_t owner); -static void LeadingCompoundStatement(statement_t owner); -static void LeadingVarDeclare(void); -static void LeadingLineSpecial(boolean executewait); -static void LeadingFunction(boolean executewait); -static void LeadingIdentifier(void); -static void BuildPrintString(void); -static void ActionOnCharRange(boolean write); -static void LeadingStrcpy(void); -static void LeadingPrint(void); -static void LeadingHudMessage(void); -static void LeadingMorphActor(void); -static void LeadingVarAssign(symbolNode_t *sym); -static pcd_t GetAssignPCD(tokenType_t token, symbolType_t symbol); -static void LeadingInternFunc(symbolNode_t *sym); -static void LeadingScriptFunc(symbolNode_t *sym); -static void LeadingSuspend(void); -static void LeadingTerminate(void); -static void LeadingRestart(void); -static void LeadingReturn(void); -static void LeadingIf(void); -static void LeadingFor(void); -static void LeadingWhileUntil(void); -static void LeadingDo(void); -static void LeadingSwitch(void); -static void LeadingCase(void); -static void LeadingDefault(void); -static void LeadingBreak(void); -static void LeadingContinue(void); -static void LeadingCreateTranslation(void); -static void LeadingIncDec(int token); -static void PushCase(int value, boolean isDefault); -static caseInfo_t *GetCaseInfo(void); -static int CaseInfoCmp(const void *a, const void *b); -static boolean DefaultInCurrent(void); -static void PushBreak(void); -static void WriteBreaks(void); -static boolean BreakAncestor(void); -static void PushContinue(void); -static void WriteContinues(int address); -static boolean ContinueAncestor(void); -static void ProcessInternFunc(symbolNode_t *sym); -static void ProcessScriptFunc(symbolNode_t *sym, boolean discardReturn); -static void EvalExpression(void); -static void ExprLevX(int level); -static void ExprLevA(void); -static void ExprFactor(void); -static void ExprTernary(void); -static void ConstExprFactor(void); -static void SendExprCommand(pcd_t pcd); -static void PushExStk(int value); -static int PopExStk(void); -static pcd_t TokenToPCD(tokenType_t token); -static pcd_t GetPushVarPCD(symbolType_t symType); -static pcd_t GetIncDecPCD(tokenType_t token, symbolType_t symbol); -static int EvalConstExpression(void); -static void ParseArrayDims(int *size, int *ndim, int dims[MAX_ARRAY_DIMS]); -static void SymToArray(int symtype, symbolNode_t *sym, int index, int ndim, int size, int dims[MAX_ARRAY_DIMS]); -static void ParseArrayIndices(symbolNode_t *sym, int requiredIndices); -static void InitializeArray(symbolNode_t *sym, int dims[MAX_ARRAY_DIMS], int size); -static void InitializeScriptArray(symbolNode_t *sym, int dims[MAX_ARRAY_DIMS]); -static symbolNode_t *DemandSymbol(char *name); -static symbolNode_t *SpeculateSymbol(char *name, boolean hasReturn); -static symbolNode_t *SpeculateFunction(const char *name, boolean hasReturn); -static void UnspeculateFunction(symbolNode_t *sym); -static void AddScriptFuncRef(symbolNode_t *sym, int address, int argcount); -static void CheckForUndefinedFunctions(void); -static void SkipBraceBlock(int depth); - -// EXTERNAL DATA DECLARATIONS ---------------------------------------------- - -// PUBLIC DATA DEFINITIONS ------------------------------------------------- - -int pa_ScriptCount; -struct ScriptTypes *pa_TypedScriptCounts; -int pa_MapVarCount; -int pa_WorldVarCount; -int pa_GlobalVarCount; -int pa_WorldArrayCount; -int pa_GlobalArrayCount; -enum ImportModes ImportMode = IMPORT_None; -boolean ExporterFlagged; -boolean pa_ConstExprIsString; - -// PRIVATE DATA DEFINITIONS ------------------------------------------------ - -static int ScriptVarCount; -static int ScriptArrayCount; -static int ScriptArraySize[MAX_SCRIPT_ARRAYS]; -static statement_t StatementHistory[MAX_STATEMENT_DEPTH]; -static int StatementIndex; -static breakInfo_t BreakInfo[MAX_BREAK]; -static int BreakIndex; -static continueInfo_t ContinueInfo[MAX_CONTINUE]; -static int ContinueIndex; -static caseInfo_t CaseInfo[MAX_CASE]; -static int CaseIndex; -static int StatementLevel; -static int ExprStack[EXPR_STACK_DEPTH]; -static int ExprStackIndex; -static boolean ConstantExpression; -static symbolNode_t *InsideFunction; -static prefunc_t *FillinFunctions; -static prefunc_t **FillinFunctionsLatest = &FillinFunctions; -static boolean ArrayHasStrings; - -static int AdjustStmtLevel[] = -{ - 0, // STMT_SCRIPT - 0, // STMT_IF - 0, // STMT_ELSE - 1, // STMT_DO - 1, // STMT_WHILEUNTIL - 1, // STMT_SWITCH - 1 // STMT_FOR -}; - -static boolean IsBreakRoot[] = -{ - NO, // STMT_SCRIPT - NO, // STMT_IF - NO, // STMT_ELSE - YES, // STMT_DO - YES, // STMT_WHILEUNTIL - YES, // STMT_SWITCH - YES // STMT_FOR -}; - -static boolean IsContinueRoot[] = -{ - NO, // STMT_SCRIPT - NO, // STMT_IF - NO, // STMT_ELSE - YES, // STMT_DO - YES, // STMT_WHILEUNTIL - NO, // STMT_SWITCH - YES // STMT_FOR -}; - -static tokenType_t LevAOps[] = -{ - TK_TERNARY, - TK_NONE -}; - -static tokenType_t LevBOps[] = -{ - TK_ORLOGICAL, - TK_NONE -}; - -static tokenType_t LevCOps[] = -{ - TK_ANDLOGICAL, - TK_NONE -}; - -static tokenType_t LevDOps[] = -{ - TK_ORBITWISE, - TK_NONE -}; - -static tokenType_t LevEOps[] = -{ - TK_EORBITWISE, - TK_NONE -}; - -static tokenType_t LevFOps[] = -{ - TK_ANDBITWISE, - TK_NONE -}; - -static tokenType_t LevGOps[] = -{ - TK_EQ, - TK_NE, - TK_NONE -}; - -static tokenType_t LevHOps[] = -{ - TK_LT, - TK_LE, - TK_GT, - TK_GE, - TK_NONE -}; - -static tokenType_t LevIOps[] = -{ - TK_LSHIFT, - TK_RSHIFT, - TK_NONE -}; - -static tokenType_t LevJOps[] = -{ - TK_PLUS, - TK_MINUS, - TK_NONE -}; - -static tokenType_t LevKOps[] = -{ - TK_ASTERISK, - TK_SLASH, - TK_PERCENT, - TK_NONE -}; - -static tokenType_t *OpsList[] = -{ - LevAOps, - LevBOps, - LevCOps, - LevDOps, - LevEOps, - LevFOps, - LevGOps, - LevHOps, - LevIOps, - LevJOps, - LevKOps, - NULL -}; - -static tokenType_t AssignOps[] = -{ - TK_ASSIGN, - TK_ADDASSIGN, - TK_SUBASSIGN, - TK_MULASSIGN, - TK_DIVASSIGN, - TK_MODASSIGN, - TK_ANDASSIGN, - TK_EORASSIGN, - TK_ORASSIGN, - TK_LSASSIGN, - TK_RSASSIGN, - TK_NONE -}; - -static struct ScriptTypes ScriptCounts[] = -{ - { "closed", 0, 0 }, - { "open", OPEN_SCRIPTS_BASE, 0 }, - { "respawn", RESPAWN_SCRIPTS_BASE, 0 }, - { "death", DEATH_SCRIPTS_BASE, 0 }, - { "enter", ENTER_SCRIPTS_BASE, 0 }, - { "pickup", PICKUP_SCRIPTS_BASE, 0 }, - { "bluereturn", BLUE_RETURN_SCRIPTS_BASE, 0 }, - { "redreturn", RED_RETURN_SCRIPTS_BASE, 0 }, - { "whitereturn", WHITE_RETURN_SCRIPTS_BASE, 0 }, - { "lightning", LIGHTNING_SCRIPTS_BASE, 0 }, - { "disconnect", DISCONNECT_SCRIPTS_BASE, 0 }, - { "unloading", UNLOADING_SCRIPTS_BASE, 0 }, - { "return", RETURN_SCRIPTS_BASE, 0 }, - { "event", EVENT_SCRIPTS_BASE, 0 }, - { "kill", KILL_SCRIPTS_BASE, 0 }, - { "reopen", REOPEN_SCRIPTS_BASE, 0 }, - { NULL, -1, 0 } -}; - -// CODE -------------------------------------------------------------------- - -//========================================================================== -// -// PA_Parse -// -//========================================================================== - -void PA_Parse(void) -{ - int i; - - pa_ScriptCount = 0; - pa_TypedScriptCounts = ScriptCounts; - for (i = 0; ScriptCounts[i].TypeName != NULL; i++) - { - ScriptCounts[i].TypeCount = 0; - } - pa_MapVarCount = 0; - pa_WorldVarCount = 0; - pa_GlobalVarCount = 0; - pa_WorldArrayCount = 0; - pa_GlobalArrayCount = 0; - TK_NextToken(); - Outside(); - CheckForUndefinedFunctions(); - ERR_Finish(); -} - -//========================================================================== -// -// CountScript -// -//========================================================================== - -static void CountScript(int type) -{ - int i; - - for (i = 0; ScriptCounts[i].TypeName != NULL; i++) - { - if (ScriptCounts[i].TypeBase == type) - { - if (type != 0) - { - MS_Message(MSG_DEBUG, "Script type: %s\n", - ScriptCounts[i].TypeName); - } - ScriptCounts[i].TypeCount++; - return; - } - } - return; -} - -//========================================================================== -// -// Outside -// -//========================================================================== - -static void Outside(void) -{ - boolean done; - int outertokencount; - - done = NO; - outertokencount = 0; - while(done == NO) - { - outertokencount++; - switch(tk_Token) - { - case TK_EOF: - done = YES; - break; - case TK_SCRIPT: - OuterScript(); - break; - case TK_FUNCTION: - OuterFunction(); - break; - case TK_INT: - case TK_STR: - case TK_BOOL: - OuterMapVar(NO); - break; - case TK_WORLD: - OuterWorldVar(NO); - break; - case TK_GLOBAL: - OuterWorldVar(YES); - break; - case TK_SPECIAL: - OuterSpecialDef(); - break; - case TK_NUMBERSIGN: - TK_NextToken(); - switch(tk_Token) - { - case TK_DEFINE: - OuterDefine(NO); - break; - case TK_LIBDEFINE: - OuterDefine(YES); - break; - case TK_INCLUDE: - OuterInclude(); - break; - case TK_NOCOMPACT: - if(ImportMode != IMPORT_Importing) - { - if(pc_Address != 8) - { - ERR_Error(ERR_NOCOMPACT_NOT_HERE, YES); - } - MS_Message(MSG_DEBUG, "Forcing NoShrink\n"); - pc_NoShrink = TRUE; - } - TK_NextToken(); - break; - case TK_WADAUTHOR: - if(ImportMode != IMPORT_Importing) - { - MS_Message(MSG_DEBUG, "Will write WadAuthor-compatible object\n"); - MS_Message(MSG_NORMAL, "You don't need to use #wadauthor anymore.\n"); - pc_WadAuthor = TRUE; - } - TK_NextToken(); - break; - case TK_NOWADAUTHOR: - if(ImportMode != IMPORT_Importing) - { - MS_Message(MSG_DEBUG, "Will write WadAuthor-incompatible object\n"); - pc_WadAuthor = FALSE; - } - TK_NextToken(); - break; - case TK_ENCRYPTSTRINGS: - if(ImportMode != IMPORT_Importing) - { - MS_Message(MSG_DEBUG, "Strings will be encrypted\n"); - pc_EncryptStrings = TRUE; - if(pc_EnforceHexen) - { - ERR_Error(ERR_HEXEN_COMPAT, YES); - } - } - TK_NextToken(); - break; - case TK_IMPORT: - OuterImport(); - outertokencount = 0; - break; - case TK_LIBRARY: - if (outertokencount != 1) - { - ERR_Error(ERR_LIBRARY_NOT_FIRST, YES); - } - TK_NextTokenMustBe(TK_STRING, ERR_STRING_LIT_NOT_FOUND); - if(ImportMode == IMPORT_None) - { - MS_Message(MSG_DEBUG, "Allocations modified for exporting\n"); - ImportMode = IMPORT_Exporting; - if(pc_EnforceHexen) - { - ERR_Error(ERR_HEXEN_COMPAT, YES); - } - } - else if(ImportMode == IMPORT_Importing) - { - PC_AddImport(tk_String); - ExporterFlagged = YES; - } - TK_NextToken(); - break; - case TK_REGION: // [mxd] - case TK_ENDREGION: - outertokencount--; // #region markers should not count as "real" tokens - TK_SkipLine(); - break; - default: - ERR_Error(ERR_INVALID_DIRECTIVE, YES); - TK_SkipLine(); - break; - } - break; - default: - ERR_Exit(ERR_INVALID_DECLARATOR, YES, NULL); - break; - } - } -} - -//========================================================================== -// -// OuterScript -// -//========================================================================== - -static void OuterScript(void) -{ - int scriptNumber; - symbolNode_t *sym; - int scriptType, scriptFlags; - - MS_Message(MSG_DEBUG, "---- OuterScript ----\n"); - BreakIndex = 0; - CaseIndex = 0; - StatementLevel = 0; - ScriptVarCount = 0; - ScriptArrayCount = 0; - SY_FreeLocals(); - TK_NextToken(); - - if(ImportMode == IMPORT_Importing) - { - // When importing, the script number is not recorded, because - // it might be a #define that is not included by the main .acs - // file, so processing it would generate a syntax error. - SkipBraceBlock(0); - TK_NextToken(); - return; - } - - // [RH] If you want to use script 0, it must be written as <<0>>. - // This is to avoid using it accidentally, since ZDoom uses script - // 0 to implement many of the Strife-specific line specials. - - if(tk_Token == TK_LSHIFT) - { - TK_NextTokenMustBe(TK_NUMBER, ERR_SCRIPT_OUT_OF_RANGE); - if(tk_Number != 0) - { - ERR_Exit(ERR_SCRIPT_OUT_OF_RANGE, YES, NULL); - } - TK_NextTokenMustBe(TK_RSHIFT, ERR_SCRIPT_OUT_OF_RANGE); - TK_NextToken(); - scriptNumber = 0; - } - else if(tk_Token == TK_STRING) - { // Named scripts start counting at -1 and go down from there. - if(strcasecmp("None", tk_String) == 0) - { - ERR_Error(ERR_SCRIPT_NAMED_NONE, YES, NULL); - } - scriptNumber = -1 - STR_FindInListInsensitive(STRLIST_NAMEDSCRIPTS, tk_String); - TK_NextToken(); - } - else - { - scriptNumber = EvalConstExpression(); - if(scriptNumber < 1 || scriptNumber > 32767) - { - TK_Undo(); - ERR_Error(ERR_SCRIPT_OUT_OF_RANGE, YES, NULL); - SkipBraceBlock(0); - TK_NextToken(); - return; - } - } - if (scriptNumber >= 0) - { - MS_Message(MSG_DEBUG, "Script number: %d\n", scriptNumber); - } - else - { - MS_Message(MSG_DEBUG, "Script name: %s (%d)\n", - STR_GetString(STRLIST_NAMEDSCRIPTS, -scriptNumber - 1), - scriptNumber); - } - scriptType = 0; - scriptFlags = 0; - if(tk_Token == TK_LPAREN) - { - if(TK_NextToken() == TK_VOID) - { - TK_NextTokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN); - } - else - { - TK_Undo(); - do - { - TK_NextTokenMustBe(TK_INT, ERR_BAD_VAR_TYPE); - TK_NextTokenMustBe(TK_IDENTIFIER, ERR_INVALID_IDENTIFIER); - if(ScriptVarCount == 4) - { - ERR_Error(ERR_TOO_MANY_SCRIPT_ARGS, YES); - } - if(SY_FindLocal(tk_String) != NULL) - { // Redefined - ERR_Error(ERR_REDEFINED_IDENTIFIER, YES, tk_String); - } - else if(ScriptVarCount < 4) - { - sym = SY_InsertLocal(tk_String, SY_SCRIPTVAR); - sym->info.var.index = ScriptVarCount; - ScriptVarCount++; - } - TK_NextToken(); - } while(tk_Token == TK_COMMA); - TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN); - } - TK_NextToken(); - switch(tk_Token) - { - case TK_DISCONNECT: - scriptType = DISCONNECT_SCRIPTS_BASE; - if(ScriptVarCount != 1) - { - ERR_Error(ERR_DISCONNECT_NEEDS_1_ARG, YES); - } - break; - - case TK_OPEN: - case TK_RESPAWN: - case TK_DEATH: - case TK_ENTER: - case TK_PICKUP: - case TK_BLUERETURN: - case TK_REDRETURN: - case TK_WHITERETURN: - case TK_LIGHTNING: - case TK_UNLOADING: - case TK_RETURN: - case TK_KILL: - case TK_REOPEN: - ERR_Error(ERR_UNCLOSED_WITH_ARGS, YES); - break; - - case TK_EVENT: - scriptType = EVENT_SCRIPTS_BASE; - if(ScriptVarCount != 3) - { - ERR_Error(ERR_EVENT_NEEDS_3_ARG, YES); - } - break; - - default: - TK_Undo(); - } - MS_Message(MSG_DEBUG, "Script type: %s (%d %s)\n", - scriptType == 0 ? "closed" : "disconnect", - ScriptVarCount, ScriptVarCount == 1 ? "arg" : "args"); - } - else switch (tk_Token) - { - case TK_OPEN: - scriptType = OPEN_SCRIPTS_BASE; - break; - - case TK_RESPAWN: // [BC] - scriptType = RESPAWN_SCRIPTS_BASE; - break; - - case TK_DEATH: // [BC] - scriptType = DEATH_SCRIPTS_BASE; - break; - - case TK_ENTER: // [BC] - scriptType = ENTER_SCRIPTS_BASE; - break; - - case TK_RETURN: - scriptType = RETURN_SCRIPTS_BASE; - break; - - case TK_PICKUP: // [BC] - scriptType = PICKUP_SCRIPTS_BASE; - break; - - case TK_BLUERETURN: // [BC] - scriptType = BLUE_RETURN_SCRIPTS_BASE; - break; - - case TK_REDRETURN: // [BC] - scriptType = RED_RETURN_SCRIPTS_BASE; - break; - - case TK_WHITERETURN: // [BC] - scriptType = WHITE_RETURN_SCRIPTS_BASE; - break; - - case TK_LIGHTNING: - scriptType = LIGHTNING_SCRIPTS_BASE; - break; - - case TK_UNLOADING: - scriptType = UNLOADING_SCRIPTS_BASE; - break; - - case TK_DISCONNECT: - scriptType = DISCONNECT_SCRIPTS_BASE; - ERR_Error (ERR_DISCONNECT_NEEDS_1_ARG, YES); - break; - - case TK_EVENT: // [BB] - scriptType = EVENT_SCRIPTS_BASE; - ERR_Error (ERR_EVENT_NEEDS_3_ARG, YES); - break; - - case TK_KILL: // [JM] - scriptType = KILL_SCRIPTS_BASE; - break; - - case TK_REOPEN: // [Nash] - scriptType = REOPEN_SCRIPTS_BASE; - break; - - default: - ERR_Error(ERR_BAD_SCRIPT_DECL, YES); - SkipBraceBlock(0); - TK_NextToken(); - return; - } - TK_NextToken(); - if(tk_Token == TK_NET) - { - scriptFlags |= NET_SCRIPT_FLAG; - TK_NextToken(); - } - // [BB] If NET and CLIENTSIDE are specified, this construction can only parse - // "NET CLIENTSIDE" but not "CLIENTSIDE NET". - if(tk_Token == TK_CLIENTSIDE) - { - scriptFlags |= CLIENTSIDE_SCRIPT_FLAG; - TK_NextToken(); - } - CountScript(scriptType); - PC_AddScript(scriptNumber, scriptType, scriptFlags, ScriptVarCount); - pc_LastAppendedCommand = PCD_NOP; - if(ProcessStatement(STMT_SCRIPT) == NO) - { - ERR_Error(ERR_INVALID_STATEMENT, YES); - } - if(pc_LastAppendedCommand != PCD_TERMINATE) - { - PC_AppendCmd(PCD_TERMINATE); - } - PC_SetScriptVarCount(scriptNumber, scriptType, ScriptVarCount, ScriptArrayCount, ScriptArraySize); - pa_ScriptCount++; -} - -//========================================================================== -// -// OuterFunction -// -//========================================================================== - -static void OuterFunction(void) -{ - enum ImportModes importing; - boolean hasReturn; - symbolNode_t *sym; - int defLine; - - MS_Message(MSG_DEBUG, "---- OuterFunction ----\n"); - importing = ImportMode; - BreakIndex = 0; - CaseIndex = 0; - StatementLevel = 0; - ScriptVarCount = 0; - ScriptArrayCount = 0; - SY_FreeLocals(); - TK_NextToken(); - if(tk_Token != TK_STR && tk_Token != TK_INT && - tk_Token != TK_VOID && tk_Token != TK_BOOL) - { - ERR_Error(ERR_BAD_RETURN_TYPE, YES); - tk_Token = TK_VOID; - } - hasReturn = tk_Token != TK_VOID; - TK_NextTokenMustBe(TK_IDENTIFIER, ERR_INVALID_IDENTIFIER); - sym = SY_FindGlobal(tk_String); - if(sym != NULL) - { - if(sym->type != SY_SCRIPTFUNC) - { // Redefined - ERR_Error(ERR_REDEFINED_IDENTIFIER, YES, tk_String); - SkipBraceBlock(0); - TK_NextToken(); - return; - } - if(!sym->info.scriptFunc.predefined) - { - ERR_Error(ERR_FUNCTION_ALREADY_DEFINED, YES); - ERR_ErrorAt(sym->info.scriptFunc.sourceName, sym->info.scriptFunc.sourceLine); - ERR_Error(ERR_NONE, YES, "Previous definition was here."); - SkipBraceBlock(0); - TK_NextToken(); - return; - } - if(sym->info.scriptFunc.hasReturnValue && !hasReturn) - { - ERR_Error(ERR_PREVIOUS_NOT_VOID, YES); - ERR_ErrorAt(sym->info.scriptFunc.sourceName, sym->info.scriptFunc.sourceLine); - ERR_Error(ERR_NONE, YES, "Previous use was here."); - } - } - else - { - sym = SY_InsertGlobal(tk_String, SY_SCRIPTFUNC); - if (importing == IMPORT_Importing) - { - sym->info.scriptFunc.address = 0; - sym->info.scriptFunc.predefined = NO; - } - else - { - sym->info.scriptFunc.address = pc_Address; - sym->info.scriptFunc.predefined = YES; - // only for consistency with other speculated functions and pretty logs - sym->info.scriptFunc.funcNumber = 0; - } - } - defLine = tk_Line; - - TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN); - if(TK_NextToken() == TK_VOID) - { - TK_NextTokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN); - } - else - { - TK_Undo(); - do - { - symbolType_t type; - symbolNode_t *local; - - TK_NextToken(); -/* if(tk_Token != TK_INT && tk_Token != TK_STR && tk_Token != TK_BOOL) - { - ERR_Error(ERR_BAD_VAR_TYPE, YES); - tk_Token = TK_INT; - } -*/ if(tk_Token == TK_INT || tk_Token == TK_BOOL) - { - if(TK_NextToken() == TK_LBRACKET) - { - TK_NextTokenMustBe(TK_RBRACKET, ERR_BAD_VAR_TYPE); - type = SY_SCRIPTALIAS; - } - else - { - TK_Undo(); - type = SY_SCRIPTVAR; - } - } - else if(tk_Token == TK_STR) - { - type = SY_SCRIPTVAR; - } - else - { - type = SY_SCRIPTVAR; - ERR_Error(ERR_BAD_VAR_TYPE, YES); - tk_Token = TK_INT; - } - TK_NextTokenMustBe(TK_IDENTIFIER, ERR_INVALID_IDENTIFIER); - if(SY_FindLocal(tk_String) != NULL) - { // Redefined - ERR_Error(ERR_REDEFINED_IDENTIFIER, YES, tk_String); - } - else - { - local = SY_InsertLocal(tk_String, type); - local->info.var.index = ScriptVarCount; - ScriptVarCount++; - } - TK_NextToken(); - } while(tk_Token == TK_COMMA); - TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN); - } - if(pc_EnforceHexen) - { - ERR_Error(ERR_HEXEN_COMPAT, YES); - } - - sym->info.scriptFunc.sourceLine = defLine; - sym->info.scriptFunc.sourceName = tk_SourceName; - sym->info.scriptFunc.argCount = ScriptVarCount; - sym->info.scriptFunc.address = (importing == IMPORT_Importing) ? 0 : pc_Address; - sym->info.scriptFunc.hasReturnValue = hasReturn; - - if(importing == IMPORT_Importing) - { - SkipBraceBlock(0); - TK_NextToken(); - sym->info.scriptFunc.predefined = NO; - sym->info.scriptFunc.varCount = ScriptVarCount; - return; - } - - TK_NextToken(); - InsideFunction = sym; - pc_LastAppendedCommand = PCD_NOP; - - // If we just call ProcessStatement(STMT_SCRIPT), and this function - // needs to return a value but the last pcode output was not a return, - // then the line number given in the error can be confusing because it - // is beyond the end of the function. To avoid this, we process the - // compound statement ourself and check if it returned something - // before checking for the '}'. If a return is required, then the error - // line will be shown as the one that contains the '}' (if present). - - TK_TokenMustBe(TK_LBRACE, ERR_MISSING_LBRACE); - TK_NextToken(); - do {} while(ProcessStatement(STMT_SCRIPT) == YES); - - if(pc_LastAppendedCommand != PCD_RETURNVOID && - pc_LastAppendedCommand != PCD_RETURNVAL) - { - if(hasReturn) - { - TK_Undo(); - ERR_Error(ERR_MUST_RETURN_A_VALUE, YES, NULL); - } - PC_AppendCmd(PCD_RETURNVOID); - } - - TK_TokenMustBe(TK_RBRACE, ERR_INVALID_STATEMENT); - TK_NextToken(); - - sym->info.scriptFunc.predefined = NO; - sym->info.scriptFunc.varCount = ScriptVarCount - - sym->info.scriptFunc.argCount; - PC_AddFunction(sym, ScriptArrayCount, ScriptArraySize); - UnspeculateFunction(sym); - InsideFunction = NULL; -} - -//========================================================================== -// -// OuterMapVar -// -//========================================================================== - -static void OuterMapVar(boolean local) -{ - symbolNode_t *sym = NULL; - int index; - - MS_Message(MSG_DEBUG, "---- %s ----\n", local ? "LeadingStaticVarDeclare" : "OuterMapVar"); - do - { - if(pa_MapVarCount >= MAX_MAP_VARIABLES) - { - ERR_Error(ERR_TOO_MANY_MAP_VARS, YES); - index = MAX_MAP_VARIABLES; - } - TK_NextTokenMustBe(TK_IDENTIFIER, ERR_INVALID_IDENTIFIER); - sym = local ? SY_FindLocal(tk_String) - : SY_FindGlobal(tk_String); - if(sym != NULL) - { // Redefined - ERR_Error(ERR_REDEFINED_IDENTIFIER, YES, tk_String); - index = MAX_MAP_VARIABLES; - } - else - { - sym = local ? SY_InsertLocal(tk_String, SY_MAPVAR) - : SY_InsertGlobal(tk_String, SY_MAPVAR); - if(ImportMode == IMPORT_Importing) - { - sym->info.var.index = index = 0; - } - else - { - sym->info.var.index = index = pa_MapVarCount; - if (!local) - { // Local variables are not exported - PC_NameMapVariable(index, sym); - } - pa_MapVarCount++; - } - } - TK_NextToken(); - if(tk_Token == TK_ASSIGN) - { - if(ImportMode != IMPORT_Importing) - { - TK_NextToken(); - PC_PutMapVariable (index, EvalConstExpression()); - } - else - { - // When importing, skip the initializer, because we don't care. - do - { - TK_NextToken(); - } while(tk_Token != TK_COMMA && tk_Token != TK_SEMICOLON); - } - } - else if(tk_Token == TK_LBRACKET) - { - int size, ndim, dims[MAX_ARRAY_DIMS]; - - ParseArrayDims(&size, &ndim, dims); - - if(sym != NULL) - { - if(ImportMode != IMPORT_Importing) - { - PC_AddArray(index, size); - } - SymToArray(SY_MAPARRAY, sym, index, size, ndim, dims); - if(tk_Token == TK_ASSIGN) - { - InitializeArray(sym, dims, size); - } - } - } - } while(tk_Token == TK_COMMA); - TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON); - TK_NextToken(); -} - -//========================================================================== -// -// OuterWorldVar -// -//========================================================================== - -static void OuterWorldVar(boolean isGlobal) -{ - int index; - symbolNode_t *sym; - - MS_Message(MSG_DEBUG, "---- Outer%sVar ----\n", isGlobal ? "Global" : "World"); - if(TK_NextToken() != TK_INT) - { - if(tk_Token != TK_BOOL) - { - TK_TokenMustBe(TK_STR, ERR_BAD_VAR_TYPE); - } - } - do - { - TK_NextTokenMustBe(TK_NUMBER, ERR_MISSING_WVAR_INDEX); - if(tk_Number >= (isGlobal ? MAX_GLOBAL_VARIABLES : MAX_WORLD_VARIABLES)) - { - ERR_Error(ERR_BAD_WVAR_INDEX+isGlobal, YES); - index = 0; - } - else - { - index = tk_Number; - } - TK_NextTokenMustBe(TK_COLON, ERR_MISSING_WVAR_COLON+isGlobal); - TK_NextTokenMustBe(TK_IDENTIFIER, ERR_INVALID_IDENTIFIER); - if(SY_FindGlobal(tk_String) != NULL) - { // Redefined - ERR_Error(ERR_REDEFINED_IDENTIFIER, YES, tk_String); - } - else - { - TK_NextToken(); - if(tk_Token == TK_LBRACKET) - { - TK_NextToken (); - if(tk_Token != TK_RBRACKET) - { - ERR_Error(ERR_NO_NEED_ARRAY_SIZE, YES); - TK_SkipPast(TK_RBRACKET); - } - else - { - TK_NextToken(); - } - if(tk_Token == TK_LBRACKET) - { - ERR_Error(ERR_NO_MULTIDIMENSIONS, YES); - do - { - TK_SkipPast(TK_RBRACKET); - } - while(tk_Token == TK_LBRACKET); - } - sym = SY_InsertGlobal(tk_String, isGlobal ? SY_GLOBALARRAY : SY_WORLDARRAY); - sym->info.array.index = index; - sym->info.array.ndim = 1; - sym->info.array.size = 0x7fffffff; // not used - memset(sym->info.array.dimensions, 0, sizeof(sym->info.array.dimensions)); - - if (isGlobal) - pa_GlobalArrayCount++; - else - pa_WorldArrayCount++; - } - else - { - sym = SY_InsertGlobal(tk_String, isGlobal ? SY_GLOBALVAR : SY_WORLDVAR); - sym->info.var.index = index; - if (isGlobal) - pa_GlobalVarCount++; - else - pa_WorldVarCount++; - } - } - } while(tk_Token == TK_COMMA); - TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON); - TK_NextToken(); -} - -//========================================================================== -// -// OuterSpecialDef -// -//========================================================================== - -static void OuterSpecialDef(void) -{ - int special; - symbolNode_t *sym; - - MS_Message(MSG_DEBUG, "---- OuterSpecialDef ----\n"); - if(ImportMode == IMPORT_Importing) - { - // No need to process special definitions when importing. - TK_SkipPast(TK_SEMICOLON); - } - else - { - do - { - if (TK_NextToken() == TK_MINUS) - { - TK_NextTokenMustBe(TK_NUMBER, ERR_MISSING_SPEC_VAL); - special = -tk_Number; - } - else - { - TK_TokenMustBe(TK_NUMBER, ERR_MISSING_SPEC_VAL); - special = tk_Number; - } - TK_NextTokenMustBe(TK_COLON, ERR_MISSING_SPEC_COLON); - TK_NextTokenMustBe(TK_IDENTIFIER, ERR_INVALID_IDENTIFIER); - sym = SY_InsertGlobalUnique(tk_String, SY_SPECIAL); - TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN); - TK_NextTokenMustBe(TK_NUMBER, ERR_MISSING_SPEC_ARGC); - sym->info.special.value = special; - sym->info.special.argCount = tk_Number | (tk_Number << 16); - TK_NextToken(); - if(tk_Token == TK_COMMA) - { // Get maximum arg count - TK_NextTokenMustBe(TK_NUMBER, ERR_MISSING_SPEC_ARGC); - sym->info.special.argCount = - (sym->info.special.argCount & 0xffff) | (tk_Number << 16); - } - else - { - TK_Undo (); - } - TK_NextTokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN); - TK_NextToken(); - } while(tk_Token == TK_COMMA); - TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON); - TK_NextToken(); - } -} - -//========================================================================== -// -// OuterDefine -// -//========================================================================== - -static void OuterDefine(boolean force) -{ - int value; - symbolNode_t *sym; - - MS_Message(MSG_DEBUG, "---- OuterDefine %s----\n", - force ? "(forced) " : ""); - TK_NextTokenMustBe(TK_IDENTIFIER, ERR_INVALID_IDENTIFIER); - sym = SY_InsertGlobalUnique(tk_String, SY_CONSTANT); - // Defines inside an import are deleted when the import is popped. - if(ImportMode != IMPORT_Importing || force) - { - sym->info.constant.fileDepth = 0; - } - else - { - sym->info.constant.fileDepth = TK_GetDepth(); - } - - TK_NextToken(); - value = EvalConstExpression(); - MS_Message(MSG_DEBUG, "Constant value: %d\n", value); - sym->info.constant.value = value; - sym->info.constant.strValue = pa_ConstExprIsString ? strdup(STR_Get(value)) : NULL; -} - -//========================================================================== -// -// OuterInclude -// -//========================================================================== - -static void OuterInclude(void) -{ - // Don't include inside an import - if(ImportMode != IMPORT_Importing) - { - MS_Message(MSG_DEBUG, "---- OuterInclude ----\n"); - TK_NextTokenMustBe(TK_STRING, ERR_STRING_LIT_NOT_FOUND); - TK_Include(tk_String); - } - else - { - TK_NextToken(); - } - TK_NextToken(); -} - -//========================================================================== -// -// OuterImport -// -//========================================================================== - -static void OuterImport(void) -{ - - MS_Message(MSG_DEBUG, "---- OuterImport ----\n"); - if(ImportMode == IMPORT_Importing) - { - // Don't import inside an import - TK_NextToken(); - } - else - { - MS_Message(MSG_DEBUG, "Importing a file\n"); - TK_NextTokenMustBe(TK_STRING, ERR_STRING_LIT_NOT_FOUND); - TK_Import(tk_String, ImportMode); - } - TK_NextToken(); -} - -//========================================================================== -// -// ProcessStatement -// -//========================================================================== - -static boolean ProcessStatement(statement_t owner) -{ - if(StatementIndex == MAX_STATEMENT_DEPTH) - { - ERR_Exit(ERR_STATEMENT_OVERFLOW, YES); - } - StatementHistory[StatementIndex++] = owner; - StatementLevel += AdjustStmtLevel[owner]; - switch(tk_Token) - { - case TK_INT: - case TK_STR: - case TK_BOOL: - case TK_STATIC: - LeadingVarDeclare(); - break; - case TK_LINESPECIAL: - if (tk_SpecialValue >= 0) - { - LeadingLineSpecial(NO); - } - else - { - LeadingFunction(NO); - } - break; - case TK_ACSEXECUTEWAIT: - if(InsideFunction) - { - ERR_Error(ERR_LATENT_IN_FUNC, YES); - } - tk_SpecialArgCount = 1 | (5<<16); - tk_SpecialValue = 80; - LeadingLineSpecial(YES); - break; - case TK_ACSNAMEDEXECUTEWAIT: - if(InsideFunction) - { - ERR_Error(ERR_LATENT_IN_FUNC, YES); - } - tk_SpecialArgCount = 1 | (5<<16); - tk_SpecialValue = -39; - LeadingFunction(YES); - break; - case TK_RESTART: - LeadingRestart(); - break; - case TK_SUSPEND: - LeadingSuspend(); - break; - case TK_TERMINATE: - LeadingTerminate(); - break; - case TK_RETURN: - LeadingReturn(); - break; - case TK_IDENTIFIER: - LeadingIdentifier(); - break; - case TK_PRINT: - case TK_PRINTBOLD: - case TK_LOG: - LeadingPrint(); - break; - - case TK_STRPARAM_EVAL: - LeadingPrint(); - PC_AppendCmd(PCD_DROP); - /* Duplicate code: LeadingPrint() post-processing: */ - TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON); - TK_NextToken(); - break; - - case TK_STRCPY: - LeadingStrcpy(); - PC_AppendCmd(PCD_DROP); - TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON); - TK_NextToken(); - break; - - case TK_HUDMESSAGE: - case TK_HUDMESSAGEBOLD: - LeadingHudMessage(); - break; - case TK_MORPHACTOR: - LeadingMorphActor(); - PC_AppendCmd(PCD_DROP); - TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON); - TK_NextToken(); - break; - case TK_IF: - LeadingIf(); - break; - case TK_FOR: - LeadingFor(); - break; - case TK_WHILE: - case TK_UNTIL: - LeadingWhileUntil(); - break; - case TK_DO: - LeadingDo(); - break; - case TK_SWITCH: - LeadingSwitch(); - break; - case TK_CASE: - if(owner != STMT_SWITCH) - { - ERR_Error(ERR_CASE_NOT_IN_SWITCH, YES); - TK_SkipPast(TK_COLON); - } - else - { - LeadingCase(); - } - break; - case TK_DEFAULT: - if(owner != STMT_SWITCH) - { - ERR_Error(ERR_DEFAULT_NOT_IN_SWITCH, YES); - TK_SkipPast(TK_COLON); - } - else if(DefaultInCurrent() == YES) - { - ERR_Error(ERR_MULTIPLE_DEFAULT, YES); - TK_SkipPast(TK_COLON); - } - else - { - LeadingDefault(); - } - break; - case TK_BREAK: - if(BreakAncestor() == NO) - { - ERR_Error(ERR_MISPLACED_BREAK, YES); - TK_SkipPast(TK_SEMICOLON); - } - else - { - LeadingBreak(); - } - break; - case TK_CONTINUE: - if(ContinueAncestor() == NO) - { - ERR_Error(ERR_MISPLACED_CONTINUE, YES); - TK_SkipPast(TK_SEMICOLON); - } - else - { - LeadingContinue(); - } - break; - case TK_CREATETRANSLATION: - LeadingCreateTranslation(); - break; - case TK_LBRACE: - LeadingCompoundStatement(owner); - break; - case TK_SEMICOLON: - TK_NextToken(); - break; - case TK_INC: - case TK_DEC: - LeadingIncDec(tk_Token); - break; - - default: - StatementIndex--; - StatementLevel -= AdjustStmtLevel[owner]; - return NO; - break; - } - StatementIndex--; - StatementLevel -= AdjustStmtLevel[owner]; - return YES; -} - -//========================================================================== -// -// LeadingCompoundStatement -// -//========================================================================== - -static void LeadingCompoundStatement(statement_t owner) -{ - //StatementLevel += AdjustStmtLevel[owner]; - TK_NextToken(); // Eat the TK_LBRACE - do {} while(ProcessStatement(owner) == YES); - TK_TokenMustBe(TK_RBRACE, ERR_INVALID_STATEMENT); - TK_NextToken(); - //StatementLevel -= AdjustStmtLevel[owner]; -} - -//========================================================================== -// -// LeadingVarDeclare -// -//========================================================================== - -static void LeadingVarDeclare(void) -{ - symbolNode_t *sym = NULL; - - if(tk_Token == TK_STATIC) - { - TK_NextToken(); - if(tk_Token != TK_INT && tk_Token != TK_STR && tk_Token != TK_BOOL) - { - ERR_Error(ERR_BAD_VAR_TYPE, YES); - TK_Undo(); - } - OuterMapVar(YES); - return; - } - - MS_Message(MSG_DEBUG, "---- LeadingVarDeclare ----\n"); - do - { - TK_NextTokenMustBe(TK_IDENTIFIER, ERR_INVALID_IDENTIFIER); -#if 0 - if(ScriptVarCount == MAX_SCRIPT_VARIABLES) - { - ERR_Error(InsideFunction - ? ERR_TOO_MANY_FUNCTION_VARS - : ERR_TOO_MANY_SCRIPT_VARS, - YES, NULL); - ScriptVarCount++; - } - else -#endif - if(SY_FindLocal(tk_String) != NULL) - { // Redefined - ERR_Error(ERR_REDEFINED_IDENTIFIER, YES, tk_String); - } - else - { - sym = SY_InsertLocal(tk_String, SY_SCRIPTVAR); - sym->info.var.index = ScriptVarCount; - ScriptVarCount++; - } - TK_NextToken(); - if(tk_Token == TK_LBRACKET) - { - int size, ndim, dims[MAX_ARRAY_DIMS]; - - ParseArrayDims(&size, &ndim, dims); - if(sym != NULL) - { - ScriptVarCount--; - if(ScriptArrayCount == MAX_SCRIPT_ARRAYS) - { - ERR_Error(InsideFunction ? ERR_TOO_MANY_FUNCTION_ARRAYS : ERR_TOO_MANY_SCRIPT_ARRAYS, YES, NULL); - } - if(ScriptArrayCount < MAX_SCRIPT_ARRAYS) - { - ScriptArraySize[ScriptArrayCount] = size; - } - SymToArray(SY_SCRIPTARRAY, sym, ScriptArrayCount++, size, ndim, dims); - if(tk_Token == TK_ASSIGN) - { - InitializeScriptArray(sym, dims); - } - } - } - else if(tk_Token == TK_ASSIGN) - { - TK_NextToken(); - EvalExpression(); - if(sym != NULL) - { - PC_AppendCmd(PCD_ASSIGNSCRIPTVAR); - PC_AppendShrink(sym->info.var.index); - } - } - } while(tk_Token == TK_COMMA); - TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON); - TK_NextToken(); -} - -//========================================================================== -// -// LeadingLineSpecial -// -//========================================================================== - -static void LeadingLineSpecial(boolean executewait) -{ - int i; - int argCount; - int argCountMin; - int argCountMax; - int argSave[8]; - U_INT specialValue; - boolean direct; - - MS_Message(MSG_DEBUG, "---- LeadingLineSpecial ----\n"); - argCountMin = tk_SpecialArgCount & 0xffff; - argCountMax = tk_SpecialArgCount >> 16; - specialValue = tk_SpecialValue; - TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN); - i = 0; - if(argCountMax > 0) - { - if(TK_NextToken() == TK_CONST) - { - TK_NextTokenMustBe(TK_COLON, ERR_MISSING_COLON); - direct = YES; - } - else - { - TK_Undo(); - direct = NO; - } - do - { - if(i == argCountMax) - { - ERR_Error(ERR_BAD_LSPEC_ARG_COUNT, YES); - i = argCountMax+1; - } - TK_NextToken(); - if(direct == YES) - { - argSave[i] = EvalConstExpression(); - } - else - { - EvalExpression(); - if (i == 0 && executewait) - { - PC_AppendCmd(PCD_DUP); - } - } - if(i < argCountMax) - { - i++; - } - } while(tk_Token == TK_COMMA); - if(i < argCountMin) - { - ERR_Error(ERR_BAD_LSPEC_ARG_COUNT, YES); - TK_SkipPast(TK_SEMICOLON); - return; - } - argCount = i; - } - else - { - // [RH] I added some zero-argument specials without realizing that - // ACS won't allow for less than one, so fake them as one-argument - // specials with a parameter of 0. - argCount = 1; - direct = YES; - argSave[0] = 0; - TK_NextToken (); - } - TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN); - TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON); - if (specialValue > 255) - { - for(; argCount < 5; ++argCount) - { - PC_AppendPushVal(0); - } - PC_AppendCmd(PCD_LSPEC5EX); - PC_AppendInt(specialValue); - if(executewait) - { - PC_AppendCmd(PCD_SCRIPTWAITDIRECT); - PC_AppendInt(argSave[0]); - } - } - else if(direct == NO) - { - PC_AppendCmd(PCD_LSPEC1+(argCount-1)); - if(pc_NoShrink) - { - PC_AppendInt(specialValue); - } - else - { - if (specialValue > 255) - { - ERR_Error(ERR_SPECIAL_RANGE, YES); - } - PC_AppendByte((U_BYTE)specialValue); - } - if(executewait) - { - PC_AppendCmd(PCD_SCRIPTWAIT); - } - } - else - { - boolean useintform; - - if(pc_NoShrink) - { - PC_AppendCmd(PCD_LSPEC1DIRECT+(argCount-1)); - PC_AppendInt(specialValue); - useintform = YES; - } - else - { - useintform = NO; - for (i = 0; i < argCount; i++) - { - if ((U_INT)argSave[i] > 255) - { - useintform = YES; - break; - } - } - PC_AppendCmd((argCount-1)+(useintform?PCD_LSPEC1DIRECT:PCD_LSPEC1DIRECTB)); - PC_AppendByte((U_BYTE)specialValue); - } - if (useintform) - { - for (i = 0; i < argCount; i++) - { - PC_AppendInt(argSave[i]); - } - } - else - { - for (i = 0; i < argCount; i++) - { - PC_AppendByte((U_BYTE)argSave[i]); - } - } - if(executewait) - { - PC_AppendCmd(PCD_SCRIPTWAITDIRECT); - PC_AppendInt(argSave[0]); - } - } - TK_NextToken(); -} - -//========================================================================== -// -// LeadingFunction -// -//========================================================================== - -static void LeadingFunction(boolean executewait) -{ - int i; - int argCount; - int argCountMin; - int argCountMax; - int specialValue; - - MS_Message(MSG_DEBUG, "---- LeadingFunction ----\n"); - argCountMin = tk_SpecialArgCount & 0xffff; - argCountMax = tk_SpecialArgCount >> 16; - specialValue = -tk_SpecialValue; - TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN); - i = 0; - if(argCountMax > 0) - { - if(TK_NextToken() == TK_CONST) - { - // Just skip const declarators - TK_NextTokenMustBe(TK_COLON, ERR_MISSING_COLON); - } - else - { - TK_Undo(); - } - do - { - if(i == argCountMax) - { - ERR_Error(ERR_BAD_ARG_COUNT, YES); - i = argCountMax+1; - } - TK_NextToken(); - EvalExpression(); - if (i == 0 && executewait) - { - PC_AppendCmd(PCD_DUP); - } - if(i < argCountMax) - { - i++; - } - } while(tk_Token == TK_COMMA); - if(i < argCountMin) - { - ERR_Error(ERR_BAD_ARG_COUNT, YES); - TK_SkipPast(TK_SEMICOLON); - return; - } - argCount = i; - } - else - { - argCount = 0; - TK_NextToken (); - } - TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN); - TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON); - PC_AppendCmd(PCD_CALLFUNC); - if(pc_NoShrink) - { - PC_AppendInt(argCount); - PC_AppendInt(specialValue); - } - else - { - PC_AppendByte((U_BYTE)argCount); - PC_AppendWord((U_WORD)specialValue); - } - PC_AppendCmd(PCD_DROP); - if(executewait) - { - PC_AppendCmd(PCD_SCRIPTWAITNAMED); - } - TK_NextToken(); -} - -//========================================================================== -// -// LeadingIdentifier -// -//========================================================================== - -static void LeadingIdentifier(void) -{ - symbolNode_t *sym; - - sym = SpeculateSymbol(tk_String, NO); - switch(sym->type) - { - case SY_MAPARRAY: - case SY_SCRIPTVAR: - case SY_SCRIPTALIAS: - case SY_MAPVAR: - case SY_WORLDVAR: - case SY_GLOBALVAR: - case SY_SCRIPTARRAY: - case SY_WORLDARRAY: - case SY_GLOBALARRAY: - LeadingVarAssign(sym); - break; - case SY_INTERNFUNC: - LeadingInternFunc(sym); - break; - case SY_SCRIPTFUNC: - LeadingScriptFunc(sym); - break; - default: - break; - } -} - -//========================================================================== -// -// LeadingInternFunc -// -//========================================================================== - -static void LeadingInternFunc(symbolNode_t *sym) -{ - if(InsideFunction && sym->info.internFunc.latent) - { - ERR_Error(ERR_LATENT_IN_FUNC, YES); - } - ProcessInternFunc(sym); - if(sym->info.internFunc.hasReturnValue == YES) - { - PC_AppendCmd(PCD_DROP); - } - TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON); - TK_NextToken(); -} - -//========================================================================== -// -// ProcessInternFunc -// -//========================================================================== - -static void ProcessInternFunc(symbolNode_t *sym) -{ - int i; - int argCount; - int optMask; - int outMask; - boolean direct; - boolean specialDirect; - int argSave[8]; - - MS_Message(MSG_DEBUG, "---- ProcessInternFunc ----\n"); - argCount = sym->info.internFunc.argCount; - optMask = sym->info.internFunc.optMask; - outMask = sym->info.internFunc.outMask; - TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN); - if(TK_NextToken() == TK_CONST) - { - TK_NextTokenMustBe(TK_COLON, ERR_MISSING_COLON); - if(sym->info.internFunc.directCommand == PCD_NOP) - { - ERR_Error(ERR_NO_DIRECT_VER, YES, NULL); - direct = NO; - specialDirect = NO; - } - else - { - direct = YES; - if (pc_NoShrink || argCount > 2 || - (sym->info.internFunc.directCommand != PCD_DELAYDIRECT && - sym->info.internFunc.directCommand != PCD_RANDOMDIRECT)) - { - specialDirect = NO; - PC_AppendCmd(sym->info.internFunc.directCommand); - } - else - { - specialDirect = YES; - } - } - TK_NextToken(); - } - else - { - direct = NO; - specialDirect = NO; // keep GCC quiet - } - i = 0; - if(argCount > 0) - { - if(tk_Token == TK_RPAREN) - { - ERR_Error(ERR_MISSING_PARAM, YES); - } - else - { - TK_Undo(); // Adjust for first expression - do - { - if(i == argCount) - { - ERR_Error(ERR_BAD_ARG_COUNT, YES); - TK_SkipTo(TK_SEMICOLON); - TK_Undo(); - return; - } - TK_NextToken(); - if(direct == YES) - { - if (tk_Token != TK_COMMA) - { - if (specialDirect) - { - argSave[i] = EvalConstExpression(); - } - else - { - PC_AppendInt(EvalConstExpression()); - } - } - else - { - if (optMask & 1) - { - if (specialDirect) - { - argSave[i] = 0; - } - else - { - PC_AppendInt(0); - } - } - else - { - ERR_Error(ERR_MISSING_PARAM, YES); - } - } - } - else - { - if (tk_Token != TK_COMMA) - { - if (!(outMask & 1)) - { - EvalExpression(); - } - else if (tk_Token != TK_IDENTIFIER) - { - ERR_Error (ERR_PARM_MUST_BE_VAR, YES); - do - { - TK_NextToken(); - } while (tk_Token != TK_COMMA && tk_Token != TK_RPAREN); - } - else - { - symbolNode_t *sym = DemandSymbol (tk_String); - PC_AppendCmd (PCD_PUSHNUMBER); - switch (sym->type) - { - case SY_SCRIPTVAR: - PC_AppendInt(sym->info.var.index | OUTVAR_SCRIPT_SPEC); - break; - case SY_MAPVAR: - PC_AppendInt(sym->info.var.index | OUTVAR_MAP_SPEC); - break; - case SY_WORLDVAR: - PC_AppendInt(sym->info.var.index | OUTVAR_WORLD_SPEC); - break; - case SY_GLOBALVAR: - PC_AppendInt(sym->info.var.index | OUTVAR_GLOBAL_SPEC); - break; - default: - ERR_Error (ERR_PARM_MUST_BE_VAR, YES); - do - { - TK_NextToken(); - } while (tk_Token != TK_COMMA && tk_Token != TK_RPAREN); - break; - } - TK_NextToken (); - } - } - else - { - if (optMask & 1) - { - PC_AppendPushVal(0); - } - else - { - ERR_Error(ERR_MISSING_PARAM, YES); - } - } - } - i++; - optMask >>= 1; - outMask >>= 1; - } while(tk_Token == TK_COMMA); - } - } - while (i < argCount && (optMask & 1)) - { - if (direct == YES) - { - if (specialDirect) - { - argSave[i] = 0; - } - else - { - PC_AppendInt(0); - } - } - else - { - PC_AppendPushVal(0); - } - i++; - optMask >>= 1; - } - if(i != argCount && i > 0) - { - ERR_Error(ERR_BAD_ARG_COUNT, YES); - } - TK_TokenMustBe(TK_RPAREN, argCount > 0 ? ERR_MISSING_RPAREN : ERR_BAD_ARG_COUNT); - if(direct == NO) - { - PC_AppendCmd(sym->info.internFunc.stackCommand); - } - else if (specialDirect) - { - boolean useintform = NO; - pcd_t shortpcd; - - switch (sym->info.internFunc.directCommand) - { - case PCD_DELAYDIRECT: - shortpcd = PCD_DELAYDIRECTB; - break; - case PCD_RANDOMDIRECT: - shortpcd = PCD_RANDOMDIRECTB; - break; - default: - useintform = YES; - shortpcd = PCD_NOP; - break; - } - - if (!useintform) - { - for (i = 0; i < argCount; i++) - { - if ((U_INT)argSave[i] > 255) - { - useintform = YES; - break; - } - } - } - - if (useintform) - { - PC_AppendCmd(sym->info.internFunc.directCommand); - for (i = 0; i < argCount; i++) - { - PC_AppendInt (argSave[i]); - } - } - else - { - PC_AppendCmd (shortpcd); - for (i = 0; i < argCount; i++) - { - PC_AppendByte ((U_BYTE)argSave[i]); - } - } - } - TK_NextToken(); -} - -//========================================================================== -// -// LeadingScriptFunc -// -//========================================================================== - -static void LeadingScriptFunc(symbolNode_t *sym) -{ - ProcessScriptFunc(sym, YES); - TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON); - TK_NextToken(); -} - - -//========================================================================== -// -// ProcessScriptFunc -// -//========================================================================== - -static void ProcessScriptFunc(symbolNode_t *sym, boolean discardReturn) -{ - int i; - int argCount; - - MS_Message(MSG_DEBUG, "---- ProcessScriptFunc ----\n"); - if(sym->info.scriptFunc.predefined == YES && discardReturn == NO) - { - sym->info.scriptFunc.hasReturnValue = YES; - } - argCount = sym->info.scriptFunc.argCount; - TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN); - i = 0; - if(argCount == 0) - { - TK_NextTokenMustBe(TK_RPAREN, ERR_BAD_ARG_COUNT); - } - else if(argCount > 0) - { - TK_NextToken(); - if(tk_Token == TK_RPAREN) - { - ERR_Error(ERR_BAD_ARG_COUNT, YES); - TK_SkipTo(TK_SEMICOLON); - return; - } - TK_Undo(); - do - { - if(i == argCount) - { - ERR_Error(ERR_BAD_ARG_COUNT, YES); - TK_SkipTo(TK_SEMICOLON); - return; - } - TK_NextToken(); - if (tk_Token != TK_COMMA) - { - EvalExpression(); - } - else - { - ERR_Error(ERR_MISSING_PARAM, YES); - TK_SkipTo(TK_SEMICOLON); - return; - } - i++; - } while(tk_Token == TK_COMMA); - } - if(argCount < 0) - { // Function has not been defined yet, so assume arg count is correct - TK_NextToken(); - while (tk_Token != TK_RPAREN) - { - EvalExpression(); - i++; - if (tk_Token == TK_COMMA) - { - TK_NextToken(); - } - else if (tk_Token != TK_RPAREN) - { - ERR_Error(ERR_MISSING_PARAM, YES); - TK_SkipTo(TK_SEMICOLON); - return; - } - } - } - else if(i != argCount) - { - ERR_Error(ERR_BAD_ARG_COUNT, YES); - TK_SkipTo(TK_SEMICOLON); - return; - } - TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN); - PC_AppendCmd(discardReturn ? PCD_CALLDISCARD : PCD_CALL); - if(sym->info.scriptFunc.predefined && ImportMode != IMPORT_Importing) - { - AddScriptFuncRef(sym, pc_Address, i); - } - if (pc_NoShrink) - { - PC_AppendInt(sym->info.scriptFunc.funcNumber); - } - else - { - PC_AppendByte((U_BYTE)sym->info.scriptFunc.funcNumber); - } - TK_NextToken(); -} - -//========================================================================== -// -// BuildPrintString -// -//========================================================================== - -static void BuildPrintString(void) -{ - pcd_t printCmd; - - do - { - switch(TK_NextCharacter()) - { - case 'a': // character array support [JB] - ActionOnCharRange(NO); - continue; - case 's': // string - printCmd = PCD_PRINTSTRING; - break; - case 'l': // [RH] localized string - printCmd = PCD_PRINTLOCALIZED; - break; - case 'i': // integer - case 'd': // decimal - printCmd = PCD_PRINTNUMBER; - break; - case 'c': // character - printCmd = PCD_PRINTCHARACTER; - break; - case 'n': // [BC] name - printCmd = PCD_PRINTNAME; - break; - case 'f': // [RH] fixed point - printCmd = PCD_PRINTFIXED; - break; - case 'k': // [GRB] key binding - printCmd = PCD_PRINTBIND; - break; - case 'b': // [RH] binary integer - printCmd = PCD_PRINTBINARY; - break; - case 'x': // [RH] hexadecimal integer - printCmd = PCD_PRINTHEX; - break; - default: - printCmd = PCD_PRINTSTRING; - ERR_Error(ERR_UNKNOWN_PRTYPE, YES); - break; - } - TK_NextTokenMustBe(TK_COLON, ERR_MISSING_COLON); - TK_NextToken(); - EvalExpression(); - PC_AppendCmd(printCmd); - } while(tk_Token == TK_COMMA); -} - -//========================================================================== -// -// ActionOnCharRange // FDARI (mutation of PrintCharArray // JB) -// -//========================================================================== - -static void ActionOnCharRange(boolean write) -{ - boolean rangeConstraints; - symbolNode_t *sym; - TK_NextTokenMustBe(TK_COLON, ERR_MISSING_COLON); - TK_NextToken(); - - if (tk_Token == TK_LPAREN) - { - rangeConstraints = YES; - TK_NextToken(); - } - else - { - rangeConstraints = NO; - } - - sym = SpeculateSymbol(tk_String, NO); - if((sym->type != SY_MAPARRAY) && (sym->type != SY_WORLDARRAY) - && (sym->type != SY_GLOBALARRAY) && (sym->type != SY_SCRIPTARRAY)) - { - ERR_Error(ERR_NOT_AN_ARRAY, YES, sym->name); - } - TK_NextToken(); - if(sym->info.array.ndim > 1) - { - ParseArrayIndices(sym, sym->info.array.ndim-1); - } - else - { - PC_AppendPushVal(0); - } - - PC_AppendPushVal(sym->info.array.index); - - - if (rangeConstraints) - { - switch (tk_Token) - { - case TK_RPAREN: - rangeConstraints = NO; - TK_NextToken(); - break; - case TK_COMMA: - TK_NextToken(); - EvalExpression(); - - switch (tk_Token) - { - case TK_RPAREN: - TK_NextToken(); - PC_AppendPushVal(0x7FFFFFFF); - break; - case TK_COMMA: - TK_NextToken(); - EvalExpression(); // limit on capacity - TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN); - TK_NextToken(); - break; - default: - ERR_Error(ERR_MISSING_RPAREN, YES); - break; - } - - break; - default: - ERR_Error(ERR_MISSING_RPAREN, YES); - break; - } - } - - if (write) - { - if (!rangeConstraints) - { - PC_AppendPushVal(0); - PC_AppendPushVal(0x7FFFFFFF); - } - - TK_TokenMustBe(TK_COMMA, ERR_MISSING_COMMA); - TK_NextToken(); - EvalExpression(); - - if (tk_Token == TK_COMMA) - { - TK_NextToken(); - EvalExpression(); - } - else - { - PC_AppendPushVal(0); - } - } - - if(sym->type == SY_SCRIPTARRAY) - { - if (write) PC_AppendCmd(PCD_STRCPYTOSCRIPTCHRANGE); - else PC_AppendCmd( rangeConstraints ? PCD_PRINTSCRIPTCHRANGE : PCD_PRINTSCRIPTCHARARRAY ); - } - else if(sym->type == SY_MAPARRAY) - { - if (write) PC_AppendCmd(PCD_STRCPYTOMAPCHRANGE); - else PC_AppendCmd( rangeConstraints ? PCD_PRINTMAPCHRANGE : PCD_PRINTMAPCHARARRAY ); - } - else if(sym->type == SY_WORLDARRAY) - { - if (write) PC_AppendCmd(PCD_STRCPYTOWORLDCHRANGE); - else PC_AppendCmd( rangeConstraints ? PCD_PRINTWORLDCHRANGE : PCD_PRINTWORLDCHARARRAY ); - } - else // if(sym->type == SY_GLOBALARRAY) - { - if (write) PC_AppendCmd(PCD_STRCPYTOGLOBALCHRANGE); - else PC_AppendCmd( rangeConstraints ? PCD_PRINTGLOBALCHRANGE : PCD_PRINTGLOBALCHARARRAY ); - } -} - -//========================================================================== -// -// LeadingStrcpy -// -//========================================================================== - -static void LeadingStrcpy(void) -{ - MS_Message(MSG_DEBUG, "---- LeadingStrcpy ----\n"); - TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN); - - switch(TK_NextCharacter()) // structure borrowed from printbuilder - { - case 'a': - ActionOnCharRange(YES); - break; - - default: - ERR_Error(ERR_UNKNOWN_PRTYPE, YES); - break; - } - - TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN); -} - -//========================================================================== -// -// LeadingPrint -// -//========================================================================== - -static void LeadingPrint(void) -{ - tokenType_t stmtToken; - - MS_Message(MSG_DEBUG, "---- LeadingPrint ----\n"); - stmtToken = tk_Token; // Will be TK_PRINT or TK_PRINTBOLD, TK_LOG or TK_STRPARAM_EVAL [FDARI] - PC_AppendCmd(PCD_BEGINPRINT); - TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN); - BuildPrintString(); - TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN); - - switch (stmtToken) - { - case TK_PRINT: - PC_AppendCmd(PCD_ENDPRINT); - break; - - case TK_PRINTBOLD: - PC_AppendCmd(PCD_ENDPRINTBOLD); - break; - - case TK_STRPARAM_EVAL: - PC_AppendCmd(PCD_SAVESTRING); - return; // THE CALLER MUST DO THE POST-PROCESSING - - case TK_LOG: - default: - PC_AppendCmd(PCD_ENDLOG); - break; - } - - TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON); - TK_NextToken(); -} - -//========================================================================== -// -// LeadingHudMessage -// -// hudmessage(str text; int type, int id, int color, fixed x, fixed y, fixed holdtime, ...) -// -//========================================================================== - -static void LeadingHudMessage(void) -{ - tokenType_t stmtToken; - int i; - - MS_Message(MSG_DEBUG, "---- LeadingHudMessage ----\n"); - stmtToken = tk_Token; // Will be TK_HUDMESSAGE or TK_HUDMESSAGEBOLD - PC_AppendCmd(PCD_BEGINPRINT); - TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN); - BuildPrintString(); - TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_PARAM); - PC_AppendCmd(PCD_MOREHUDMESSAGE); - for (i = 6; i > 0; i--) - { - TK_NextToken(); - EvalExpression(); - if (i > 1) - TK_TokenMustBe(TK_COMMA, ERR_MISSING_PARAM); - } - if (tk_Token == TK_COMMA) - { // HUD message has optional parameters - PC_AppendCmd(PCD_OPTHUDMESSAGE); - do - { - TK_NextToken(); - EvalExpression(); - } while (tk_Token == TK_COMMA); - } - TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN); - PC_AppendCmd(stmtToken == TK_HUDMESSAGE ? - PCD_ENDHUDMESSAGE : PCD_ENDHUDMESSAGEBOLD); - TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON); - TK_NextToken(); -} - -//========================================================================== -// -// LeadingMorphActor -// -// MorphActor(int tid, [str playerclass, [str monsterclass, [int duration, [int style, [str morphflash, [str unmorphflash]]]]]]) -// -//========================================================================== - -static void LeadingMorphActor(void) -{ - int i; - byte strMask; - - MS_Message(MSG_DEBUG, "---- LeadingMorphActor ----\n"); - strMask = 0b01100110; - - TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN); - if(TK_NextToken() == TK_CONST) - { - TK_NextTokenMustBe(TK_COLON, ERR_MISSING_COLON); - ERR_Error(ERR_NO_DIRECT_VER, YES, NULL); - TK_NextToken(); - } - i = 0; - if(tk_Token == TK_RPAREN) - { - ERR_Error(ERR_MISSING_PARAM, YES); - } - else - { - TK_Undo(); // Adjust for first expression - do - { - if(i == 7) - { - ERR_Error(ERR_BAD_ARG_COUNT, YES); - TK_SkipTo(TK_SEMICOLON); - TK_Undo(); - return; - } - TK_NextToken(); - - if(tk_Token != TK_COMMA) - { - EvalExpression(); - } - else - { - if(i > 0) - { - if(strMask & 1) - { - PC_AppendPushVal(STR_Find("")); - } - else - { - PC_AppendPushVal(0); - } - } - else - { - ERR_Error(ERR_MISSING_PARAM, YES); - } - } - i++; - strMask >>= 1; - } while(tk_Token == TK_COMMA); - } - while(i < 7) - { - if(strMask & 1) - { - PC_AppendPushVal(STR_Find("")); - } - else - { - PC_AppendPushVal(0); - } - i++; - strMask >>= 1; - } - if(i != 7) - { - ERR_Error(ERR_BAD_ARG_COUNT, YES); - } - TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN); - PC_AppendCmd(PCD_MORPHACTOR); -} - -//========================================================================== -// -// LeadingCreateTranslation -// -// Simple grammar: -// -// tranlationstmt: CreateTranslation ( exp opt_args ) ; -// opt_args: /* empty: just reset the translation */ | , arglist -// arglist: arg | arglist arg -// arg: range = replacement -// range: exp : exp -// replacement: palrep | colorrep | desatrep | colouriserep | tintrep -// palrep: exp : exp -// colorrep: [exp,exp,exp]:[exp,exp,exp] -// desatrep: %colorrep -// colouriserep: #[exp,exp,exp] -// tintrep: @exp[exp,exp,exp] -//========================================================================== - -static void LeadingCreateTranslation(void) -{ - MS_Message(MSG_DEBUG, "---- LeadingCreateTranslation ----\n"); - TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN); - TK_NextToken(); - EvalExpression(); - PC_AppendCmd(PCD_STARTTRANSLATION); - while (tk_Token == TK_COMMA) - { - pcd_t translationcode; - - TK_NextToken(); - EvalExpression(); // Get first palette entry in range - TK_TokenMustBe(TK_COLON, ERR_MISSING_COLON); - TK_NextToken(); - EvalExpression(); // Get second palette entry in range - TK_TokenMustBe(TK_ASSIGN, ERR_MISSING_ASSIGN); - - TK_NextToken(); - if(tk_Token == TK_PERCENT) - { - translationcode = PCD_TRANSLATIONRANGE3; - TK_NextTokenMustBe(TK_LBRACKET, ERR_MISSING_LBRACKET); - } - else if (tk_Token == TK_NUMBERSIGN) - { - translationcode = PCD_TRANSLATIONRANGE4; - TK_NextTokenMustBe(TK_LBRACKET, ERR_MISSING_LBRACKET); - } - else if (tk_Token == TK_ATSIGN) - { - translationcode = PCD_TRANSLATIONRANGE5; - TK_NextToken(); - EvalExpression(); - TK_TokenMustBe(TK_LBRACKET, ERR_MISSING_LBRACKET); - } - else - { - translationcode = PCD_TRANSLATIONRANGE2; - } - if(tk_Token == TK_LBRACKET) - { // Replacement is color range - int i, j; - - TK_NextToken(); - - for(j = 2; j != 0; --j) - { - for(i = 3; i != 0; --i) - { - EvalExpression(); - if(i != 1) - { - TK_TokenMustBe(TK_COMMA, ERR_MISSING_COMMA); - } - else - { - TK_TokenMustBe(TK_RBRACKET, ERR_MISSING_RBRACKET); - } - TK_NextToken(); - } - if (translationcode == PCD_TRANSLATIONRANGE4 || translationcode == PCD_TRANSLATIONRANGE5) - break; - if(j == 2) - { - TK_TokenMustBe(TK_COLON, ERR_MISSING_COLON); - TK_NextTokenMustBe(TK_LBRACKET, ERR_MISSING_LBRACKET); - TK_NextToken(); - } - } - } - else - { // Replacement is palette range - EvalExpression(); - TK_TokenMustBe(TK_COLON, ERR_MISSING_COLON); - TK_NextToken(); - EvalExpression(); - translationcode = PCD_TRANSLATIONRANGE1; - } - PC_AppendCmd(translationcode); - } - PC_AppendCmd(PCD_ENDTRANSLATION); - TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN); - TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON); - TK_NextToken(); -} - -//========================================================================== -// -// LeadingIf -// -//========================================================================== - -static void LeadingIf(void) -{ - int jumpAddrPtr1; - int jumpAddrPtr2; - - MS_Message(MSG_DEBUG, "---- LeadingIf ----\n"); - TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN); - TK_NextToken(); - EvalExpression(); - TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN); - PC_AppendCmd(PCD_IFNOTGOTO); - jumpAddrPtr1 = pc_Address; - PC_SkipInt(); - TK_NextToken(); - if(ProcessStatement(STMT_IF) == NO) - { - ERR_Error(ERR_INVALID_STATEMENT, YES); - } - if(tk_Token == TK_ELSE) - { - PC_AppendCmd(PCD_GOTO); - jumpAddrPtr2 = pc_Address; - PC_SkipInt(); - PC_WriteInt(pc_Address, jumpAddrPtr1); - TK_NextToken(); - if(ProcessStatement(STMT_ELSE) == NO) - { - ERR_Error(ERR_INVALID_STATEMENT, YES); - } - PC_WriteInt(pc_Address, jumpAddrPtr2); - } - else - { - PC_WriteInt(pc_Address, jumpAddrPtr1); - } -} - -//========================================================================== -// -// LeadingFor -// -//========================================================================== - -static void LeadingFor(void) -{ - int exprAddr; - int incAddr; - int ifgotoAddr; - int gotoAddr; - - MS_Message(MSG_DEBUG, "---- LeadingFor ----\n"); - TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN); - TK_NextToken(); - if(ProcessStatement(STMT_IF) == NO) - { - ERR_Error(ERR_INVALID_STATEMENT, YES); - } - exprAddr = pc_Address; - EvalExpression(); - TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON); - TK_NextToken(); - PC_AppendCmd(PCD_IFGOTO); - ifgotoAddr = pc_Address; - PC_SkipInt(); - PC_AppendCmd(PCD_GOTO); - gotoAddr = pc_Address; - PC_SkipInt(); - incAddr = pc_Address; - forSemicolonHack = TRUE; - if(ProcessStatement(STMT_IF) == NO) - { - ERR_Error(ERR_INVALID_STATEMENT, YES); - } - forSemicolonHack = FALSE; - PC_AppendCmd(PCD_GOTO); - PC_AppendInt(exprAddr); - PC_WriteInt(pc_Address,ifgotoAddr); - if(ProcessStatement(STMT_FOR) == NO) - { - ERR_Error(ERR_INVALID_STATEMENT, YES); - } - PC_AppendCmd(PCD_GOTO); - PC_AppendInt(incAddr); - WriteContinues(incAddr); - WriteBreaks(); - PC_WriteInt(pc_Address,gotoAddr); -} - -//========================================================================== -// -// LeadingWhileUntil -// -//========================================================================== - -static void LeadingWhileUntil(void) -{ - tokenType_t stmtToken; - int topAddr; - int outAddrPtr; - - MS_Message(MSG_DEBUG, "---- LeadingWhileUntil ----\n"); - stmtToken = tk_Token; - topAddr = pc_Address; - TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN); - TK_NextToken(); - EvalExpression(); - TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN); - PC_AppendCmd(stmtToken == TK_WHILE ? PCD_IFNOTGOTO : PCD_IFGOTO); - outAddrPtr = pc_Address; - PC_SkipInt(); - TK_NextToken(); - if(ProcessStatement(STMT_WHILEUNTIL) == NO) - { - ERR_Error(ERR_INVALID_STATEMENT, YES); - } - PC_AppendCmd(PCD_GOTO); - PC_AppendInt(topAddr); - - PC_WriteInt(pc_Address, outAddrPtr); - - WriteContinues(topAddr); - WriteBreaks(); -} - -//========================================================================== -// -// LeadingDo -// -//========================================================================== - -static void LeadingDo(void) -{ - int topAddr; - int exprAddr; - tokenType_t stmtToken; - - MS_Message(MSG_DEBUG, "---- LeadingDo ----\n"); - topAddr = pc_Address; - TK_NextToken(); - if(ProcessStatement(STMT_DO) == NO) - { - ERR_Error(ERR_INVALID_STATEMENT, YES, NULL); - } - if(tk_Token != TK_WHILE && tk_Token != TK_UNTIL) - { - ERR_Error(ERR_BAD_DO_STATEMENT, YES, NULL); - TK_SkipPast(TK_SEMICOLON); - return; - } - stmtToken = tk_Token; - TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN); - exprAddr = pc_Address; - TK_NextToken(); - EvalExpression(); - TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN); - TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON); - PC_AppendCmd(stmtToken == TK_WHILE ? PCD_IFGOTO : PCD_IFNOTGOTO); - PC_AppendInt(topAddr); - WriteContinues(exprAddr); - WriteBreaks(); - TK_NextToken(); -} - -//========================================================================== -// -// LeadingSwitch -// -//========================================================================== - -static void LeadingSwitch(void) -{ - int switcherAddrPtr; - int outAddrPtr; - caseInfo_t *cInfo; - int defaultAddress; - - MS_Message(MSG_DEBUG, "---- LeadingSwitch ----\n"); - - TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN); - TK_NextToken(); - EvalExpression(); - TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN); - - PC_AppendCmd(PCD_GOTO); - switcherAddrPtr = pc_Address; - PC_SkipInt(); - - TK_NextToken(); - if(ProcessStatement(STMT_SWITCH) == NO) - { - ERR_Error(ERR_INVALID_STATEMENT, YES, NULL); - } - - PC_AppendCmd(PCD_GOTO); - outAddrPtr = pc_Address; - PC_SkipInt(); - - PC_WriteInt(pc_Address, switcherAddrPtr); - defaultAddress = 0; - - if(pc_HexenCase) - { - while((cInfo = GetCaseInfo()) != NULL) - { - if(cInfo->isDefault == YES) - { - defaultAddress = cInfo->address; - continue; - } - PC_AppendCmd(PCD_CASEGOTO); - PC_AppendInt(cInfo->value); - PC_AppendInt(cInfo->address); - } - } - else if(CaseIndex != 0) - { - caseInfo_t *maxCase = &CaseInfo[CaseIndex]; - caseInfo_t *minCase = maxCase; - - // [RH] Sort cases so that the VM can handle them with - // a quick binary search. - while((cInfo = GetCaseInfo()) != NULL) - { - minCase = cInfo; - } - qsort(minCase, maxCase - minCase, sizeof(caseInfo_t), CaseInfoCmp); - if(minCase->isDefault == YES) - { - defaultAddress = minCase->address; - minCase++; - } - if (minCase < maxCase) - { - PC_AppendCmd(PCD_CASEGOTOSORTED); - if(pc_Address%4 != 0) - { // Align to a 4-byte boundary - U_INT pad = 0; - PC_Append((void *)&pad, 4-(pc_Address%4)); - } - PC_AppendInt(maxCase - minCase); - for(; minCase < maxCase; ++minCase) - { - PC_AppendInt(minCase->value); - PC_AppendInt(minCase->address); - } - } - } - PC_AppendCmd(PCD_DROP); - - if(defaultAddress != 0) - { - PC_AppendCmd(PCD_GOTO); - PC_AppendInt(defaultAddress); - } - - PC_WriteInt(pc_Address, outAddrPtr); - - WriteBreaks(); -} - -//========================================================================== -// -// LeadingCase -// -//========================================================================== - -static void LeadingCase(void) -{ - MS_Message(MSG_DEBUG, "---- LeadingCase ----\n"); - TK_NextToken(); - PushCase(EvalConstExpression(), NO); - TK_TokenMustBe(TK_COLON, ERR_MISSING_COLON); - TK_NextToken(); -} - -//========================================================================== -// -// LeadingDefault -// -//========================================================================== - -static void LeadingDefault(void) -{ - MS_Message(MSG_DEBUG, "---- LeadingDefault ----\n"); - TK_NextTokenMustBe(TK_COLON, ERR_MISSING_COLON); - PushCase(0, YES); - TK_NextToken(); -} - -//========================================================================== -// -// PushCase -// -//========================================================================== - -static void PushCase(int value, boolean isDefault) -{ - if(CaseIndex == MAX_CASE) - { - ERR_Exit(ERR_CASE_OVERFLOW, YES); - } - CaseInfo[CaseIndex].level = StatementLevel; - CaseInfo[CaseIndex].value = value; - CaseInfo[CaseIndex].isDefault = isDefault; - CaseInfo[CaseIndex].address = pc_Address; - CaseIndex++; -} - -//========================================================================== -// -// GetCaseInfo -// -//========================================================================== - -static caseInfo_t *GetCaseInfo(void) -{ - if(CaseIndex == 0) - { - return NULL; - } - if(CaseInfo[CaseIndex-1].level > StatementLevel) - { - return &CaseInfo[--CaseIndex]; - } - return NULL; -} - -//========================================================================== -// -// CaseInfoCmp -// -//========================================================================== - -static int CaseInfoCmp (const void *a, const void *b) -{ - const caseInfo_t *ca = (const caseInfo_t *)a; - const caseInfo_t *cb = (const caseInfo_t *)b; - - // The default case always gets moved to the front. - if(ca->isDefault) - { - return -1; - } - if(cb->isDefault) - { - return 1; - } - return ca->value - cb->value; -} - -//========================================================================== -// -// DefaultInCurrent -// -//========================================================================== - -static boolean DefaultInCurrent(void) -{ - int i; - - for(i = 0; i < CaseIndex; i++) - { - if(CaseInfo[i].isDefault == YES - && CaseInfo[i].level == StatementLevel) - { - return YES; - } - } - return NO; -} - -//========================================================================== -// -// LeadingBreak -// -//========================================================================== - -static void LeadingBreak(void) -{ - MS_Message(MSG_DEBUG, "---- LeadingBreak ----\n"); - TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON); - PC_AppendCmd(PCD_GOTO); - PushBreak(); - PC_SkipInt(); - TK_NextToken(); -} - -//========================================================================== -// -// PushBreak -// -//========================================================================== - -static void PushBreak(void) -{ - if(BreakIndex == MAX_CASE) - { - ERR_Exit(ERR_BREAK_OVERFLOW, YES); - } - BreakInfo[BreakIndex].level = StatementLevel; - BreakInfo[BreakIndex].addressPtr = pc_Address; - BreakIndex++; -} - -//========================================================================== -// -// WriteBreaks -// -//========================================================================== - -static void WriteBreaks(void) -{ - while(BreakIndex && BreakInfo[BreakIndex-1].level > StatementLevel) - { - PC_WriteInt(pc_Address, BreakInfo[--BreakIndex].addressPtr); - } -} - -//========================================================================== -// -// BreakAncestor -// -// Returns YES if the current statement history contains a break root -// statement. -// -//========================================================================== - -static boolean BreakAncestor(void) -{ - int i; - - for(i = 0; i < StatementIndex; i++) - { - if(IsBreakRoot[StatementHistory[i]]) - { - return YES; - } - } - return NO; -} - -//========================================================================== -// -// LeadingContinue -// -//========================================================================== - -static void LeadingContinue(void) -{ - MS_Message(MSG_DEBUG, "---- LeadingContinue ----\n"); - TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON); - PC_AppendCmd(PCD_GOTO); - PushContinue(); - PC_SkipInt(); - TK_NextToken(); -} - -//========================================================================== -// -// PushContinue -// -//========================================================================== - -static void PushContinue(void) -{ - if(ContinueIndex == MAX_CONTINUE) - { - ERR_Exit(ERR_CONTINUE_OVERFLOW, YES); - } - ContinueInfo[ContinueIndex].level = StatementLevel; - ContinueInfo[ContinueIndex].addressPtr = pc_Address; - ContinueIndex++; -} - -//========================================================================== -// -// WriteContinues -// -//========================================================================== - -static void WriteContinues(int address) -{ - if(ContinueIndex == 0) - { - return; - } - while(ContinueInfo[ContinueIndex-1].level > StatementLevel) - { - PC_WriteInt(address, ContinueInfo[--ContinueIndex].addressPtr); - } -} - -//========================================================================== -// -// ContinueAncestor -// -//========================================================================== - -static boolean ContinueAncestor(void) -{ - int i; - - for(i = 0; i < StatementIndex; i++) - { - if(IsContinueRoot[StatementHistory[i]]) - { - return YES; - } - } - return NO; -} - -//========================================================================== -// -// LeadingIncDec -// -//========================================================================== - -static void LeadingIncDec(int token) -{ - symbolNode_t *sym; - - MS_Message(MSG_DEBUG, "---- LeadingIncDec ----\n"); - TK_NextTokenMustBe(TK_IDENTIFIER, ERR_INCDEC_OP_ON_NON_VAR); - sym = DemandSymbol(tk_String); - if(sym->type != SY_SCRIPTVAR && sym->type != SY_MAPVAR - && sym->type != SY_WORLDVAR && sym->type != SY_GLOBALVAR - && sym->type != SY_MAPARRAY && sym->type != SY_GLOBALARRAY - && sym->type != SY_WORLDARRAY && sym->type != SY_SCRIPTALIAS - && sym->type != SY_SCRIPTARRAY) - { - ERR_Error(ERR_INCDEC_OP_ON_NON_VAR, YES); - TK_SkipPast(TK_SEMICOLON); - return; - } - TK_NextToken(); - if(sym->type == SY_MAPARRAY || sym->type == SY_WORLDARRAY - || sym->type == SY_GLOBALARRAY || sym->type == SY_SCRIPTARRAY) - { - ParseArrayIndices(sym, sym->info.array.ndim); - } - else if(tk_Token == TK_LBRACKET) - { - ERR_Error(ERR_NOT_AN_ARRAY, YES, sym->name); - while(tk_Token == TK_LBRACKET) - { - TK_SkipPast(TK_RBRACKET); - } - } - PC_AppendCmd(GetIncDecPCD(token, sym->type)); - PC_AppendShrink(sym->info.var.index); - if(forSemicolonHack) - { - TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN); - } - else - { - TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON); - } - TK_NextToken(); -} - -//========================================================================== -// -// LeadingVarAssign -// -//========================================================================== - -static void LeadingVarAssign(symbolNode_t *sym) -{ - boolean done; - tokenType_t assignToken; - - MS_Message(MSG_DEBUG, "---- LeadingVarAssign ----\n"); - done = NO; - do - { - TK_NextToken(); // Fetch assignment operator - if(sym->type == SY_MAPARRAY || sym->type == SY_WORLDARRAY - || sym->type == SY_GLOBALARRAY || sym->type == SY_SCRIPTARRAY) - { - ParseArrayIndices(sym, sym->info.array.ndim); - } - else if(tk_Token == TK_LBRACKET) - { - ERR_Error(ERR_NOT_AN_ARRAY, YES, sym->name); - while(tk_Token == TK_LBRACKET) - { - TK_SkipPast(TK_RBRACKET); - } - } - if(tk_Token == TK_INC || tk_Token == TK_DEC) - { // Postfix increment or decrement - PC_AppendCmd(GetIncDecPCD(tk_Token, sym->type)); - if (pc_NoShrink) - { - PC_AppendInt(sym->info.var.index); - } - else - { - PC_AppendByte(sym->info.var.index); - } - TK_NextToken(); - } - else - { // Normal operator - if(TK_Member(AssignOps) == NO) - { - ERR_Error(ERR_MISSING_ASSIGN_OP, YES); - TK_SkipPast(TK_SEMICOLON); - return; - } - assignToken = tk_Token; - TK_NextToken(); - EvalExpression(); - PC_AppendCmd(GetAssignPCD(assignToken, sym->type)); - PC_AppendShrink(sym->info.var.index); - } - if(tk_Token == TK_COMMA) - { - TK_NextTokenMustBe(TK_IDENTIFIER, ERR_BAD_ASSIGNMENT); - sym = DemandSymbol(tk_String); - if(sym->type != SY_SCRIPTVAR && sym->type != SY_MAPVAR - && sym->type != SY_WORLDVAR && sym->type != SY_GLOBALVAR - && sym->type != SY_WORLDARRAY && sym->type != SY_GLOBALARRAY - && sym->type != SY_SCRIPTALIAS) - { - ERR_Error(ERR_BAD_ASSIGNMENT, YES); - TK_SkipPast(TK_SEMICOLON); - return; - } - } - else - { - TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON); - TK_NextToken(); - done = YES; - } - } while(done == NO); -} - -//========================================================================== -// -// GetAssignPCD -// -//========================================================================== - -static pcd_t GetAssignPCD(tokenType_t token, symbolType_t symbol) -{ - size_t i, j; - static tokenType_t tokenLookup[] = - { - TK_ASSIGN, TK_ADDASSIGN, TK_SUBASSIGN, - TK_MULASSIGN, TK_DIVASSIGN, TK_MODASSIGN, - TK_ANDASSIGN, TK_EORASSIGN, TK_ORASSIGN, - TK_LSASSIGN, TK_RSASSIGN - }; - static symbolType_t symbolLookup[] = - { - SY_SCRIPTVAR, SY_MAPVAR, SY_WORLDVAR, SY_GLOBALVAR, SY_MAPARRAY, - SY_WORLDARRAY, SY_GLOBALARRAY, SY_SCRIPTARRAY - }; - static pcd_t assignmentLookup[11][8] = - { - { PCD_ASSIGNSCRIPTVAR, PCD_ASSIGNMAPVAR, PCD_ASSIGNWORLDVAR, PCD_ASSIGNGLOBALVAR, PCD_ASSIGNMAPARRAY, PCD_ASSIGNWORLDARRAY, PCD_ASSIGNGLOBALARRAY, PCD_ASSIGNSCRIPTARRAY }, - { PCD_ADDSCRIPTVAR, PCD_ADDMAPVAR, PCD_ADDWORLDVAR, PCD_ADDGLOBALVAR, PCD_ADDMAPARRAY, PCD_ADDWORLDARRAY, PCD_ADDGLOBALARRAY, PCD_ADDSCRIPTARRAY }, - { PCD_SUBSCRIPTVAR, PCD_SUBMAPVAR, PCD_SUBWORLDVAR, PCD_SUBGLOBALVAR, PCD_SUBMAPARRAY, PCD_SUBWORLDARRAY, PCD_SUBGLOBALARRAY, PCD_SUBSCRIPTARRAY }, - { PCD_MULSCRIPTVAR, PCD_MULMAPVAR, PCD_MULWORLDVAR, PCD_MULGLOBALVAR, PCD_MULMAPARRAY, PCD_MULWORLDARRAY, PCD_MULGLOBALARRAY, PCD_MULSCRIPTARRAY }, - { PCD_DIVSCRIPTVAR, PCD_DIVMAPVAR, PCD_DIVWORLDVAR, PCD_DIVGLOBALVAR, PCD_DIVMAPARRAY, PCD_DIVWORLDARRAY, PCD_DIVGLOBALARRAY, PCD_DIVSCRIPTARRAY }, - { PCD_MODSCRIPTVAR, PCD_MODMAPVAR, PCD_MODWORLDVAR, PCD_MODGLOBALVAR, PCD_MODMAPARRAY, PCD_MODWORLDARRAY, PCD_MODGLOBALARRAY, PCD_MODSCRIPTARRAY }, - { PCD_ANDSCRIPTVAR, PCD_ANDMAPVAR, PCD_ANDWORLDVAR, PCD_ANDGLOBALVAR, PCD_ANDMAPARRAY, PCD_ANDWORLDARRAY, PCD_ANDGLOBALARRAY, PCD_ANDSCRIPTARRAY }, - { PCD_EORSCRIPTVAR, PCD_EORMAPVAR, PCD_EORWORLDVAR, PCD_EORGLOBALVAR, PCD_EORMAPARRAY, PCD_EORWORLDARRAY, PCD_EORGLOBALARRAY, PCD_EORSCRIPTARRAY }, - { PCD_ORSCRIPTVAR, PCD_ORMAPVAR, PCD_ORWORLDVAR, PCD_ORGLOBALVAR, PCD_ORMAPARRAY, PCD_ORWORLDARRAY, PCD_ORGLOBALARRAY, PCD_ORSCRIPTARRAY }, - { PCD_LSSCRIPTVAR, PCD_LSMAPVAR, PCD_LSWORLDVAR, PCD_LSGLOBALVAR, PCD_LSMAPARRAY, PCD_LSWORLDARRAY, PCD_LSGLOBALARRAY, PCD_LSSCRIPTARRAY }, - { PCD_RSSCRIPTVAR, PCD_RSMAPVAR, PCD_RSWORLDVAR, PCD_RSGLOBALVAR, PCD_RSMAPARRAY, PCD_RSWORLDARRAY, PCD_RSGLOBALARRAY, PCD_RSSCRIPTARRAY } - }; - - for(i = 0; i < ARRAY_SIZE(tokenLookup); ++i) - { - if(tokenLookup[i] == token) - { - for(j = 0; j < ARRAY_SIZE(symbolLookup); ++j) - { - if (symbolLookup[j] == symbol) - { - return assignmentLookup[i][j]; - } - } - break; - } - } - return PCD_NOP; -} - -//========================================================================== -// -// LeadingSuspend -// -//========================================================================== - -static void LeadingSuspend(void) -{ - MS_Message(MSG_DEBUG, "---- LeadingSuspend ----\n"); - if(InsideFunction) - { - ERR_Error(ERR_SUSPEND_IN_FUNCTION, YES); - } - TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON); - PC_AppendCmd(PCD_SUSPEND); - TK_NextToken(); -} - -//========================================================================== -// -// LeadingTerminate -// -//========================================================================== - -static void LeadingTerminate(void) -{ - MS_Message(MSG_DEBUG, "---- LeadingTerminate ----\n"); - if(InsideFunction) - { - ERR_Error(ERR_TERMINATE_IN_FUNCTION, YES); - } - TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON); - PC_AppendCmd(PCD_TERMINATE); - TK_NextToken(); -} - -//========================================================================== -// -// LeadingRestart -// -//========================================================================== - -static void LeadingRestart(void) -{ - MS_Message(MSG_DEBUG, "---- LeadingRestart ----\n"); - if(InsideFunction) - { - ERR_Error(ERR_RESTART_IN_FUNCTION, YES); - } - TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON); - PC_AppendCmd(PCD_RESTART); - TK_NextToken(); -} - -//========================================================================== -// -// LeadingReturn -// -//========================================================================== - -static void LeadingReturn(void) -{ - MS_Message(MSG_DEBUG, "---- LeadingReturn ----\n"); - if(!InsideFunction) - { - ERR_Error(ERR_RETURN_OUTSIDE_FUNCTION, YES); - while (TK_NextToken () != TK_SEMICOLON) - { - if (tk_Token == TK_EOF) - break; - } - } - else - { - TK_NextToken(); - if(tk_Token == TK_SEMICOLON) - { - if(InsideFunction->info.scriptFunc.hasReturnValue) - { - ERR_Error(ERR_MUST_RETURN_A_VALUE, YES); - } - PC_AppendCmd(PCD_RETURNVOID); - } - else - { - if(!InsideFunction->info.scriptFunc.hasReturnValue) - { - ERR_Error(ERR_MUST_NOT_RETURN_A_VALUE, YES); - } - EvalExpression(); - TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON); - PC_AppendCmd(PCD_RETURNVAL); - } - TK_NextToken(); - } -} - -//========================================================================== -// -// EvalConstExpression -// -//========================================================================== - -static int EvalConstExpression(void) -{ - pa_ConstExprIsString = NO; // Used by PC_PutMapVariable - ExprStackIndex = 0; - ConstantExpression = YES; - ExprLevA(); - if(ExprStackIndex != 1) - { - ERR_Error(ERR_BAD_CONST_EXPR, YES, NULL); - ExprStack[0] = 0; - ExprStackIndex = 1; - } - return PopExStk(); -} - -//========================================================================== -// -// EvalExpression -// -// [RH] Rewrote all the ExprLevA - ExprLevJ functions in favor of a single -// table-driven parser function. -// -//========================================================================== - -static void EvalExpression(void) -{ - ConstantExpression = NO; - ExprLevA(); -} - -static void ExprLevA(void) -{ - ExprLevX(0); -} - -// Operator precedence levels: -// Operator: ? : -// Operator: || -// Operator: && -// Operator: | -// Operator: ^ -// Operator: & -// Operators: == != -// Operators: < <= > >= -// Operators: << >> -// Operators: + - -// Operators: * / % - -static void ExprLevX(int level) -{ - if(OpsList[level] == NULL) - { - boolean unaryMinus; - - unaryMinus = FALSE; - if(tk_Token == TK_MINUS) - { - unaryMinus = TRUE; - TK_NextToken(); - } - if(tk_Token == TK_PLUS) - { - // Completely ignore unary plus - TK_NextToken(); - } - if(ConstantExpression == YES) - { - ConstExprFactor(); - } - else - { - ExprFactor(); - } - if(unaryMinus == TRUE) - { - SendExprCommand(PCD_UNARYMINUS); - } - } - else - { - ExprLevX(level + 1); - while(TK_Member(OpsList[level])) - { - if (tk_Token == TK_TERNARY) - { - ExprTernary(); - } - else - { - tokenType_t token = tk_Token; - TK_NextToken(); - ExprLevX(level + 1); - SendExprCommand(TokenToPCD(token)); - } - } - } -} - -static void ExprLineSpecial(void) -{ - int argCountMin = tk_SpecialArgCount & 0xffff; - int argCountMax = tk_SpecialArgCount >> 16; - int specialValue = tk_SpecialValue; - - // There are two ways to use a special in an expression: - // 1. The special name by itself returns the special's number. - // 2. The special followed by parameters actually executes the special. - TK_NextToken(); - if(tk_Token != TK_LPAREN) - { - PC_AppendPushVal(specialValue); - } - else - { - int argCount = 0; - - TK_NextToken(); - if(tk_Token != TK_RPAREN) - { - TK_Undo(); - do - { - TK_NextToken(); - EvalExpression(); - argCount++; - } while(tk_Token == TK_COMMA); - } - if(argCount < argCountMin || argCount > argCountMax) - { - ERR_Error(specialValue >=0? ERR_BAD_LSPEC_ARG_COUNT : ERR_BAD_ARG_COUNT, YES); - return; - } - if (specialValue >= 0) - { - for(; argCount < 5; ++argCount) - { - PC_AppendPushVal(0); - } - TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN); - TK_NextToken(); - PC_AppendCmd(specialValue <= 255? PCD_LSPEC5RESULT : PCD_LSPEC5EXRESULT); - if(pc_NoShrink || specialValue > 255) - { - PC_AppendInt(specialValue); - } - else - { - PC_AppendByte((U_BYTE)specialValue); - } - } - else - { - TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN); - TK_NextToken(); - PC_AppendCmd(PCD_CALLFUNC); - if(pc_NoShrink) - { - PC_AppendInt(argCount); - PC_AppendInt(-specialValue); - } - else - { - PC_AppendByte((U_BYTE)argCount); - PC_AppendWord((U_WORD)-specialValue); - } - } - } -} - -static void ExprTernary(void) -{ - int jumpAddrPtr; - - PC_AppendCmd(PCD_IFNOTGOTO); - jumpAddrPtr = pc_Address; - PC_SkipInt(); - - TK_NextToken(); - ExprLevA(); - - if(tk_Token != TK_COLON) - { - ERR_Error(ERR_BAD_EXPR, YES, NULL); - } - else - { - PC_AppendCmd(PCD_GOTO); - PC_WriteInt(pc_Address + 4, jumpAddrPtr); // int = 4 bytes - jumpAddrPtr = pc_Address; - PC_SkipInt(); - - TK_NextToken(); - ExprLevA(); - - PC_WriteInt(pc_Address, jumpAddrPtr); - } - -} - -static void ExprFactor(void) -{ - symbolNode_t *sym; - tokenType_t opToken; - - switch(tk_Token) - { - case TK_STRING: - if (ImportMode != IMPORT_Importing) - { - tk_Number = STR_Find(tk_String); - PC_AppendPushVal(tk_Number); - if (ImportMode == IMPORT_Exporting) - { - // The VM identifies strings by storing a library ID in the - // high word of the string index. The library ID is not - // known until the script actually gets loaded into the game, - // so we need to use this p-code to tack the ID of the - // currently running library to the index of the string that - // just got pushed onto the stack. - // - // Simply assuming that a string is from the current library - // is not good enough, because they can be passed around - // between libraries and the map's behavior. Thus, we need - // to know which object file a particular string belongs to. - // - // A specific example: - // A map's behavior calls a function in a library and passes - // a string: - // - // LibFunc ("The library will do something with this string."); - // - // The library function needs to know that the string originated - // outside the library. Similarly, if a library function returns - // a string, the caller needs to know that the string did not - // originate from the same object file. - // - // And that's why strings have library IDs tacked onto them. - // The map's main behavior (i.e. an object that is not a library) - // always uses library ID 0 to identify its strings, so its - // strings don't need to be tagged. - PC_AppendCmd(PCD_TAGSTRING); - } - } - TK_NextToken(); - break; - case TK_NUMBER: - PC_AppendPushVal(tk_Number); - TK_NextToken(); - break; - case TK_LPAREN: - TK_NextToken(); - ExprLevA(); - if(tk_Token != TK_RPAREN) - { - ERR_Error(ERR_BAD_EXPR, YES, NULL); - TK_SkipPast(TK_RPAREN); - } - else - { - TK_NextToken(); - } - break; - case TK_NOT: - TK_NextToken(); - ExprFactor(); - PC_AppendCmd(PCD_NEGATELOGICAL); - break; - case TK_TILDE: - TK_NextToken(); - ExprFactor(); - PC_AppendCmd(PCD_NEGATEBINARY); - break; - case TK_INC: - case TK_DEC: - opToken = tk_Token; - TK_NextTokenMustBe(TK_IDENTIFIER, ERR_INCDEC_OP_ON_NON_VAR); - sym = DemandSymbol(tk_String); - if(sym->type != SY_SCRIPTVAR && sym->type != SY_MAPVAR - && sym->type != SY_WORLDVAR && sym->type != SY_GLOBALVAR - && sym->type != SY_MAPARRAY && sym->type != SY_WORLDARRAY - && sym->type != SY_GLOBALARRAY && sym->type != SY_SCRIPTARRAY) - { - ERR_Error(ERR_INCDEC_OP_ON_NON_VAR, YES); - } - else - { - TK_NextToken(); - if(sym->type == SY_MAPARRAY || sym->type == SY_WORLDARRAY - || sym->type == SY_GLOBALARRAY || sym->type == SY_SCRIPTARRAY) - { - ParseArrayIndices(sym, sym->info.array.ndim); - PC_AppendCmd(PCD_DUP); - } - else if(tk_Token == TK_LBRACKET) - { - ERR_Error(ERR_NOT_AN_ARRAY, YES, sym->name); - while(tk_Token == TK_LBRACKET) - { - TK_SkipPast(TK_RBRACKET); - } - } - PC_AppendCmd(GetIncDecPCD(opToken, sym->type)); - PC_AppendShrink(sym->info.var.index); - PC_AppendCmd(GetPushVarPCD(sym->type)); - PC_AppendShrink(sym->info.var.index); - } - break; - case TK_IDENTIFIER: - sym = SpeculateSymbol(tk_String, YES); - switch(sym->type) - { - case SY_SCRIPTALIAS: - // FIXME - break; - case SY_SCRIPTARRAY: - case SY_MAPARRAY: - case SY_WORLDARRAY: - case SY_GLOBALARRAY: - TK_NextToken(); - ParseArrayIndices(sym, sym->info.array.ndim); - // fallthrough - case SY_SCRIPTVAR: - case SY_MAPVAR: - case SY_WORLDVAR: - case SY_GLOBALVAR: - if(sym->type != SY_MAPARRAY && sym->type != SY_WORLDARRAY - && sym->type != SY_GLOBALARRAY && sym->type != SY_SCRIPTARRAY) - { - TK_NextToken(); - if(tk_Token == TK_LBRACKET) - { - ERR_Error(ERR_NOT_AN_ARRAY, YES, sym->name); - while(tk_Token == TK_LBRACKET) - { - TK_SkipPast(TK_RBRACKET); - } - } - } - if((tk_Token == TK_INC || tk_Token == TK_DEC) - && (sym->type == SY_MAPARRAY || sym->type == SY_WORLDARRAY - || sym->type == SY_GLOBALARRAY || sym->type == SY_SCRIPTARRAY)) - { - PC_AppendCmd(PCD_DUP); - } - PC_AppendCmd(GetPushVarPCD(sym->type)); - PC_AppendShrink(sym->info.var.index); - if(tk_Token == TK_INC || tk_Token == TK_DEC) - { - if(sym->type == SY_MAPARRAY || sym->type == SY_WORLDARRAY - || sym->type == SY_GLOBALARRAY || sym->type == SY_SCRIPTARRAY) - { - PC_AppendCmd(PCD_SWAP); - } - PC_AppendCmd(GetIncDecPCD(tk_Token, sym->type)); - PC_AppendShrink(sym->info.var.index); - TK_NextToken(); - } - break; - case SY_INTERNFUNC: - if(sym->info.internFunc.hasReturnValue == NO) - { - ERR_Error(ERR_EXPR_FUNC_NO_RET_VAL, YES); - } - ProcessInternFunc(sym); - break; - case SY_SCRIPTFUNC: - if(sym->info.scriptFunc.predefined == NO - && sym->info.scriptFunc.hasReturnValue == NO) - { - ERR_Error(ERR_EXPR_FUNC_NO_RET_VAL, YES); - } - ProcessScriptFunc(sym, NO); - break; - default: - ERR_Error(ERR_ILLEGAL_EXPR_IDENT, YES, tk_String); - TK_NextToken(); - break; - } - break; - case TK_LINESPECIAL: - ExprLineSpecial(); - break; - case TK_STRPARAM_EVAL: - LeadingPrint(); - TK_NextToken(); - break; - case TK_STRCPY: - LeadingStrcpy(); - TK_NextToken(); - break; - case TK_MORPHACTOR: - LeadingMorphActor(); - TK_NextToken(); - break; - default: - ERR_Error(ERR_BAD_EXPR, YES); - TK_NextToken(); - break; - } -} - -static void ConstExprFactor(void) -{ - switch(tk_Token) - { - case TK_STRING: - if (ImportMode != IMPORT_Importing) - { - int strnum = STR_Find(tk_String); - if (ImportMode == IMPORT_Exporting) - { - pa_ConstExprIsString = YES; - } - PushExStk(strnum); - } - else - { - // Importing, so it doesn't matter - PushExStk(0); - } - TK_NextToken(); - break; - case TK_NUMBER: - PushExStk(tk_Number); - TK_NextToken(); - break; - case TK_LPAREN: - TK_NextToken(); - ExprLevA(); - if(tk_Token != TK_RPAREN) - { - ERR_Error(ERR_BAD_CONST_EXPR, YES); - TK_SkipPast(TK_RPAREN); - } - else - { - TK_NextToken(); - } - break; - case TK_NOT: - TK_NextToken(); - ConstExprFactor(); - SendExprCommand(PCD_NEGATELOGICAL); - break; - case TK_TILDE: - TK_NextToken(); - ConstExprFactor(); - SendExprCommand(PCD_NEGATEBINARY); - break; - default: - ERR_Error(ERR_BAD_CONST_EXPR, YES); - PushExStk(0); - while(tk_Token != TK_COMMA && - tk_Token != TK_SEMICOLON && - tk_Token != TK_RPAREN) - { - if(tk_Token == TK_EOF) - { - ERR_Exit(ERR_EOF, YES); - } - TK_NextToken(); - } - break; - } -} - -//========================================================================== -// -// SendExprCommand -// -//========================================================================== - -static void SendExprCommand(pcd_t pcd) -{ - int operand1, operand2; - - if(ConstantExpression == NO) - { - PC_AppendCmd(pcd); - return; - } - switch(pcd) - { - case PCD_ADD: - PushExStk(PopExStk()+PopExStk()); - break; - case PCD_SUBTRACT: - operand2 = PopExStk(); - PushExStk(PopExStk()-operand2); - break; - case PCD_MULTIPLY: - PushExStk(PopExStk()*PopExStk()); - break; - case PCD_DIVIDE: - case PCD_MODULUS: - operand2 = PopExStk(); - operand1 = PopExStk(); - if (operand2 != 0) - { - PushExStk(pcd == PCD_DIVIDE ? operand1/operand2 : operand1%operand2); - } - else - { - ERR_Error(ERR_DIV_BY_ZERO_IN_CONST_EXPR, YES); - PushExStk(operand1); - } - break; - case PCD_EQ: - PushExStk(PopExStk() == PopExStk()); - break; - case PCD_NE: - PushExStk(PopExStk() != PopExStk()); - break; - case PCD_LT: - operand2 = PopExStk(); - PushExStk(PopExStk() < operand2); - break; - case PCD_GT: - operand2 = PopExStk(); - PushExStk(PopExStk() > operand2); - break; - case PCD_LE: - operand2 = PopExStk(); - PushExStk(PopExStk() <= operand2); - break; - case PCD_GE: - operand2 = PopExStk(); - PushExStk(PopExStk() >= operand2); - break; - case PCD_ANDLOGICAL: - operand2 = PopExStk(); - operand1 = PopExStk(); - PushExStk(operand1 && operand2); - break; - case PCD_ORLOGICAL: - operand2 = PopExStk(); - operand1 = PopExStk(); - PushExStk(operand1 || operand2); - break; - case PCD_ANDBITWISE: - PushExStk(PopExStk()&PopExStk()); - break; - case PCD_ORBITWISE: - PushExStk(PopExStk()|PopExStk()); - break; - case PCD_EORBITWISE: - PushExStk(PopExStk()^PopExStk()); - break; - case PCD_NEGATELOGICAL: - PushExStk(!PopExStk()); - break; - case PCD_NEGATEBINARY: - PushExStk(~PopExStk()); - break; - case PCD_LSHIFT: - operand2 = PopExStk(); - PushExStk(PopExStk()<>operand2); - break; - case PCD_UNARYMINUS: - PushExStk(-PopExStk()); - break; - default: - ERR_Exit(ERR_UNKNOWN_CONST_EXPR_PCD, YES); - break; - } -} - -//========================================================================== -// -// PushExStk -// -//========================================================================== - -static void PushExStk(int value) -{ - if(ExprStackIndex == EXPR_STACK_DEPTH) - { - ERR_Exit(ERR_EXPR_STACK_OVERFLOW, YES); - } - ExprStack[ExprStackIndex++] = value; -} - -//========================================================================== -// -// PopExStk -// -//========================================================================== - -static int PopExStk(void) -{ - if(ExprStackIndex < 1) - { - ERR_Error(ERR_EXPR_STACK_EMPTY, YES); - return 0; - } - return ExprStack[--ExprStackIndex]; -} - -//========================================================================== -// -// TokenToPCD -// -//========================================================================== - -static pcd_t TokenToPCD(tokenType_t token) -{ - int i; - static struct - { - tokenType_t token; - pcd_t pcd; - } operatorLookup[] = - { - { TK_ORLOGICAL, PCD_ORLOGICAL }, - { TK_ANDLOGICAL, PCD_ANDLOGICAL }, - { TK_ORBITWISE, PCD_ORBITWISE }, - { TK_EORBITWISE, PCD_EORBITWISE }, - { TK_ANDBITWISE, PCD_ANDBITWISE }, - { TK_EQ, PCD_EQ }, - { TK_NE, PCD_NE }, - { TK_LT, PCD_LT }, - { TK_LE, PCD_LE }, - { TK_GT, PCD_GT }, - { TK_GE, PCD_GE }, - { TK_LSHIFT, PCD_LSHIFT }, - { TK_RSHIFT, PCD_RSHIFT }, - { TK_PLUS, PCD_ADD }, - { TK_MINUS, PCD_SUBTRACT }, - { TK_ASTERISK, PCD_MULTIPLY }, - { TK_SLASH, PCD_DIVIDE }, - { TK_PERCENT, PCD_MODULUS }, - { TK_NONE, PCD_NOP } - }; - - for(i = 0; operatorLookup[i].token != TK_NONE; i++) - { - if(operatorLookup[i].token == token) - { - return operatorLookup[i].pcd; - } - } - return PCD_NOP; -} - -//========================================================================== -// -// GetPushVarPCD -// -//========================================================================== - -static pcd_t GetPushVarPCD(symbolType_t symType) -{ - switch(symType) - { - case SY_SCRIPTVAR: - return PCD_PUSHSCRIPTVAR; - case SY_MAPVAR: - return PCD_PUSHMAPVAR; - case SY_WORLDVAR: - return PCD_PUSHWORLDVAR; - case SY_GLOBALVAR: - return PCD_PUSHGLOBALVAR; - case SY_SCRIPTARRAY: - return PCD_PUSHSCRIPTARRAY; - case SY_MAPARRAY: - return PCD_PUSHMAPARRAY; - case SY_WORLDARRAY: - return PCD_PUSHWORLDARRAY; - case SY_GLOBALARRAY: - return PCD_PUSHGLOBALARRAY; - default: - break; - } - return PCD_NOP; -} - -//========================================================================== -// -// GetIncDecPCD -// -//========================================================================== - -static pcd_t GetIncDecPCD(tokenType_t token, symbolType_t symbol) -{ - int i; - static struct - { - tokenType_t token; - symbolType_t symbol; - pcd_t pcd; - } incDecLookup[] = - { - { TK_INC, SY_SCRIPTVAR, PCD_INCSCRIPTVAR }, - { TK_INC, SY_MAPVAR, PCD_INCMAPVAR }, - { TK_INC, SY_WORLDVAR, PCD_INCWORLDVAR }, - { TK_INC, SY_GLOBALVAR, PCD_INCGLOBALVAR }, - { TK_INC, SY_SCRIPTARRAY, PCD_INCSCRIPTARRAY }, - { TK_INC, SY_MAPARRAY, PCD_INCMAPARRAY }, - { TK_INC, SY_WORLDARRAY, PCD_INCWORLDARRAY }, - { TK_INC, SY_GLOBALARRAY, PCD_INCGLOBALARRAY }, - - { TK_DEC, SY_SCRIPTVAR, PCD_DECSCRIPTVAR }, - { TK_DEC, SY_MAPVAR, PCD_DECMAPVAR }, - { TK_DEC, SY_WORLDVAR, PCD_DECWORLDVAR }, - { TK_DEC, SY_GLOBALVAR, PCD_DECGLOBALVAR }, - { TK_DEC, SY_SCRIPTARRAY, PCD_DECSCRIPTARRAY }, - { TK_DEC, SY_MAPARRAY, PCD_DECMAPARRAY }, - { TK_DEC, SY_WORLDARRAY, PCD_DECWORLDARRAY }, - { TK_DEC, SY_GLOBALARRAY, PCD_DECGLOBALARRAY }, - - { TK_NONE, SY_DUMMY, PCD_NOP } - }; - - for(i = 0; incDecLookup[i].token != TK_NONE; i++) - { - if(incDecLookup[i].token == token - && incDecLookup[i].symbol == symbol) - { - return incDecLookup[i].pcd; - } - } - return PCD_NOP; -} - -//========================================================================== -// -// ParseArrayDims -// -//========================================================================== - -static void ParseArrayDims(int *size_p, int *ndim_p, int dims[MAX_ARRAY_DIMS]) -{ - int size = 0; - int ndim = 0; - memset(dims, 0, MAX_ARRAY_DIMS*sizeof(dims[0])); - - while(tk_Token == TK_LBRACKET) - { - if(ndim == MAX_ARRAY_DIMS) - { - ERR_Error(ERR_TOO_MANY_ARRAY_DIMS, YES); - do - { - TK_NextToken(); - } while(tk_Token != TK_COMMA && tk_Token != TK_SEMICOLON); - break; - } - TK_NextToken(); - if (tk_Token == TK_RBRACKET) - { - ERR_Error(ERR_NEED_ARRAY_SIZE, YES); - } - else - { - dims[ndim] = EvalConstExpression(); - if(dims[ndim] == 0) - { - ERR_Error(ERR_ZERO_DIMENSION, YES); - dims[ndim] = 1; - } - if(ndim == 0) - { - size = dims[ndim]; - } - else - { - size *= dims[ndim]; - } - } - ndim++; - TK_TokenMustBe(TK_RBRACKET, ERR_MISSING_RBRACKET); - TK_NextToken(); - } - if(pc_EnforceHexen) - { - TK_Undo(); // backup so error pointer is on last bracket instead of following token - ERR_Error(ERR_HEXEN_COMPAT, YES); - TK_NextToken(); - } - *size_p = size; - *ndim_p = ndim; -} - -static void SymToArray(int symtype, symbolNode_t *sym, int index, int size, int ndim, int dims[MAX_ARRAY_DIMS]) -{ - int i; - - MS_Message(MSG_DEBUG, "%s changed to an array of size %d\n", sym->name, size); - sym->type = symtype; - sym->info.array.index = index; - sym->info.array.ndim = ndim; - sym->info.array.size = size; - if(ndim > 0) - { - sym->info.array.dimensions[ndim-1] = 1; - for(i = ndim - 2; i >= 0; --i) - { - sym->info.array.dimensions[i] = - sym->info.array.dimensions[i+1] * dims[i+1]; - } - } - MS_Message(MSG_DEBUG, " - with multipliers "); - for(i = 0; i < ndim; ++i) - { - MS_Message(MSG_DEBUG, "[%d]", sym->info.array.dimensions[i]); - } - MS_Message(MSG_DEBUG, "\n"); -} - -//========================================================================== -// -// ParseArrayIndices -// -//========================================================================== - -static void ParseArrayIndices(symbolNode_t *sym, int requiredIndices) -{ - boolean warned = NO; - int i; - - if(requiredIndices > 0) - { - TK_TokenMustBe(TK_LBRACKET, ERR_MISSING_LBRACKET); - } - i = 0; - while(tk_Token == TK_LBRACKET) - { - TK_NextToken(); - if(((sym->type == SY_MAPARRAY || sym->type == SY_SCRIPTARRAY) && i == requiredIndices) || - (sym->type != SY_MAPARRAY && sym->type != SY_SCRIPTARRAY && i > 0)) - { - if (!warned) - { - warned = YES; - if(sym->info.array.ndim == requiredIndices) - { - ERR_Error(ERR_TOO_MANY_DIM_USED, YES, - sym->name, sym->info.array.ndim); - } - else - { - ERR_Error(ERR_NOT_A_CHAR_ARRAY, YES, sym->name, - sym->info.array.ndim, requiredIndices); - } - } - } - EvalExpression(); - if(i < sym->info.array.ndim - 1 && sym->info.array.dimensions[i] > 1) - { - PC_AppendPushVal(sym->info.array.dimensions[i]); - PC_AppendCmd(PCD_MULTIPLY); - } - if(i > 0) - { - PC_AppendCmd(PCD_ADD); - } - i++; - TK_TokenMustBe(TK_RBRACKET, ERR_MISSING_RBRACKET); - TK_NextToken(); - } - if(i < requiredIndices) - { - ERR_Error(ERR_TOO_FEW_DIM_USED, YES, - sym->name, requiredIndices - i); - } - // if there were unspecified indices, multiply the offset by their sizes [JB] - if(requiredIndices < sym->info.array.ndim - 1) - { - int i, mult = 1; - for(i = 0; i < sym->info.array.ndim - requiredIndices - 1; ++i) - { - mult *= sym->info.array.dimensions[sym->info.array.ndim - 2 - i]; - } - if(mult > 1) - { - PC_AppendPushVal(mult); - PC_AppendCmd(PCD_MULTIPLY); - } - } -} - -//========================================================================== -// -// ProcessArrayLevel -// -//========================================================================== - -static void ProcessArrayLevel(int level, int *entry, int ndim, - int dims[MAX_ARRAY_DIMS], int muls[MAX_ARRAY_DIMS], char *name) -{ - int warned_too_many = NO; - int i; - - for(i = 0; ; ++i) - { - if(tk_Token == TK_COMMA) - { - entry += muls[level-1]; - TK_NextToken(); - } - else if(tk_Token == TK_RBRACE) - { - TK_NextToken(); - return; - } - else - { - if(level == ndim) - { - if(tk_Token == TK_LBRACE) - { - ERR_Error(ERR_TOO_MANY_DIM_USED, YES, name, ndim); - SkipBraceBlock(0); - TK_NextToken(); - entry++; - } - else - { - int val; - - if (i >= dims[level - 1] && !warned_too_many) - { - warned_too_many = YES; - ERR_Error(ERR_TOO_MANY_ARRAY_INIT, YES); - } - val = EvalConstExpression(); - ArrayHasStrings |= pa_ConstExprIsString; - if (i < dims[level - 1]) - { - entry[i] = val; - } - } - } - else - { - //Bugfix for r3226 by Zom-B - if (i >= dims[level - 1]) - { - if (!warned_too_many) - { - warned_too_many = YES; - ERR_Error(ERR_TOO_MANY_ARRAY_INIT, YES); - } - // Allow execution to continue without stray memory access - entry -= muls[level-1]; - } - TK_TokenMustBe(TK_LBRACE, ERR_MISSING_LBRACE_ARR); - TK_NextToken(); - ProcessArrayLevel(level+1, entry, ndim, dims, muls, name); - assert(level > 0); - entry += muls[level-1]; - } - if(i < dims[level-1]-1) - { - if(tk_Token != TK_RBRACE) - { - TK_TokenMustBe(TK_COMMA, ERR_MISSING_COMMA); - TK_NextToken(); - } - } - else - { - if(tk_Token != TK_COMMA) - { - TK_TokenMustBe(TK_RBRACE, ERR_MISSING_RBRACE_ARR); - } - else - { - TK_NextToken(); - } - } - } - } - TK_TokenMustBe(TK_RBRACE, ERR_MISSING_RBRACE_ARR); - TK_NextToken(); -} - -//========================================================================== -// -// InitializeArray -// -//========================================================================== - -static void InitializeArray(symbolNode_t *sym, int dims[MAX_ARRAY_DIMS], int size) -{ - static int *entries = NULL; - static int lastsize = -1; - - if(lastsize < size) - { - entries = MS_Realloc(entries, sizeof(int)*size, ERR_OUT_OF_MEMORY); - lastsize = size; - } - memset(entries, 0, sizeof(int)*size); - - TK_NextTokenMustBe(TK_LBRACE, ERR_MISSING_LBRACE_ARR); - TK_NextToken(); - ArrayHasStrings = NO; - ProcessArrayLevel(1, entries, sym->info.array.ndim, dims, - sym->info.array.dimensions, sym->name); - if(ImportMode != IMPORT_Importing) - { - PC_InitArray(sym->info.array.index, entries, ArrayHasStrings); - } -} - -//========================================================================== -// -// ProcessScriptArrayLevel -// -//========================================================================== - -static void ProcessScriptArrayLevel(int level, int loc, symbolNode_t *sym, int ndim, - int dims[MAX_ARRAY_DIMS], int muls[MAX_ARRAY_DIMS], char *name) -{ - int warned_too_many = NO; - int i; - - for(i = 0; ; ++i) - { - if(tk_Token == TK_COMMA) - { - loc += muls[level-1]; - TK_NextToken(); - } - else if(tk_Token == TK_RBRACE) - { - TK_NextToken(); - return; - } - else - { - if(level == ndim) - { - if(tk_Token == TK_LBRACE) - { - ERR_Error(ERR_TOO_MANY_DIM_USED, YES, name, ndim); - SkipBraceBlock(0); - TK_NextToken(); - loc++; - } - else - { - if(i >= dims[level - 1] && !warned_too_many) - { - warned_too_many = YES; - ERR_Error(ERR_TOO_MANY_ARRAY_INIT, YES); - } - PC_AppendPushVal(loc + i); - EvalExpression(); - PC_AppendCmd(PCD_ASSIGNSCRIPTARRAY); - PC_AppendShrink(sym->info.array.index); - } - } - else - { - //Bugfix for r3226 by Zom-B - if (i >= dims[level - 1]) - { - if (!warned_too_many) - { - warned_too_many = YES; - ERR_Error(ERR_TOO_MANY_ARRAY_INIT, YES); - } - } - TK_TokenMustBe(TK_LBRACE, ERR_MISSING_LBRACE_ARR); - TK_NextToken(); - ProcessScriptArrayLevel(level+1, loc, sym, ndim, dims, muls, name); - assert(level > 0); - loc += muls[level-1]; - } - if(i < dims[level-1]-1) - { - if(tk_Token != TK_RBRACE) - { - TK_TokenMustBe(TK_COMMA, ERR_MISSING_COMMA); - TK_NextToken(); - } - } - else - { - if(tk_Token != TK_COMMA) - { - TK_TokenMustBe(TK_RBRACE, ERR_MISSING_RBRACE_ARR); - } - else - { - TK_NextToken(); - } - } - } - } - TK_TokenMustBe(TK_RBRACE, ERR_MISSING_RBRACE_ARR); - TK_NextToken(); -} - -//========================================================================== -// -// InitializeScriptArray -// -//========================================================================== - -static void InitializeScriptArray(symbolNode_t *sym, int dims[MAX_ARRAY_DIMS]) -{ - TK_NextTokenMustBe(TK_LBRACE, ERR_MISSING_LBRACE_ARR); - TK_NextToken(); - ArrayHasStrings = NO; - ProcessScriptArrayLevel(1, 0, sym, sym->info.array.ndim, dims, - sym->info.array.dimensions, sym->name); -} - -//========================================================================== -// -// DemandSymbol -// -//========================================================================== - -static symbolNode_t *DemandSymbol(char *name) -{ - symbolNode_t *sym; - - if((sym = SY_Find(name)) == NULL) - { - ERR_Exit(ERR_UNKNOWN_IDENTIFIER, YES, name); - } - return sym; -} - -//========================================================================== -// -// SpeculateSymbol -// -//========================================================================== - -static symbolNode_t *SpeculateSymbol(char *name, boolean hasReturn) -{ - symbolNode_t *sym; - - sym = SY_Find(name); - if(sym == NULL) - { - char name[MAX_IDENTIFIER_LENGTH]; - - strcpy (name, tk_String); - TK_NextToken(); - if(tk_Token == TK_LPAREN) - { // Looks like a function call - sym = SpeculateFunction(name, hasReturn); - TK_Undo(); - } - else - { - ERR_Exit(ERR_UNKNOWN_IDENTIFIER, YES, name); - } - } - return sym; -} - -//========================================================================== -// -// SpeculateFunction -// -// Add a temporary symbol for a function that is used before it is defined. -// -//========================================================================== - -static symbolNode_t *SpeculateFunction(const char *name, boolean hasReturn) -{ - symbolNode_t *sym; - - MS_Message(MSG_DEBUG, "---- SpeculateFunction %s ----\n", name); - sym = SY_InsertGlobal(tk_String, SY_SCRIPTFUNC); - sym->info.scriptFunc.predefined = YES; - sym->info.scriptFunc.hasReturnValue = hasReturn; - sym->info.scriptFunc.sourceLine = tk_Line; - sym->info.scriptFunc.sourceName = tk_SourceName; - sym->info.scriptFunc.argCount = -1; - sym->info.scriptFunc.funcNumber = 0; - return sym; -} - -//========================================================================== -// -// UnspeculateFunction -// -// Fills in function calls that were made before this function was defined. -// -//========================================================================== - -static void UnspeculateFunction(symbolNode_t *sym) -{ - prefunc_t *fillin; - prefunc_t **prev; - - prev = &FillinFunctions; - fillin = FillinFunctions; - while(fillin != NULL) - { - prefunc_t *next = fillin->next; - if(fillin->sym == sym) - { - if(fillin->argcount != sym->info.scriptFunc.argCount) - { - ERR_ErrorAt(fillin->source, fillin->line); - ERR_Error(ERR_FUNC_ARGUMENT_COUNT, YES, sym->name, - sym->info.scriptFunc.argCount, - sym->info.scriptFunc.argCount == 1 ? "" : "s"); - } - - if(pc_NoShrink) - { - PC_WriteInt(sym->info.scriptFunc.funcNumber, fillin->address); - } - else - { - PC_WriteByte((U_BYTE)sym->info.scriptFunc.funcNumber, fillin->address); - } - if(FillinFunctionsLatest == &fillin->next) - { - FillinFunctionsLatest = prev; - } - free (fillin); - *prev = next; - } - else - { - prev = &fillin->next; - } - fillin = next; - } -} - -//========================================================================== -// -// AddScriptFuncRef -// -//========================================================================== - -static void AddScriptFuncRef(symbolNode_t *sym, int address, int argcount) -{ - prefunc_t *fillin = MS_Alloc(sizeof(*fillin), ERR_OUT_OF_MEMORY); - fillin->next = NULL; - fillin->sym = sym; - fillin->address = address; - fillin->argcount = argcount; - fillin->line = tk_Line; - fillin->source = tk_SourceName; - *FillinFunctionsLatest = fillin; - FillinFunctionsLatest = &fillin->next; -} - -//========================================================================== -// -// Check for undefined functions -// -//========================================================================== - -static void CheckForUndefinedFunctions(void) -{ - prefunc_t *fillin = FillinFunctions; - - while(fillin != NULL) - { - ERR_ErrorAt(fillin->source, fillin->line); - ERR_Error(ERR_UNDEFINED_FUNC, YES, fillin->sym->name); - fillin = fillin->next; - } -} - -//========================================================================== -// -// SkipBraceBlock -// -// If depth is 0, it scans for the first { and then starts going from there. -// At exit, the terminating } is left as the current token. -// -//========================================================================== - -void SkipBraceBlock(int depth) -{ - if (depth == 0) - { - // Find first { - while(tk_Token != TK_LBRACE) - { - if(tk_Token == TK_EOF) - { - ERR_Exit(ERR_EOF, YES, NULL); - } - TK_NextToken(); - } - depth = 1; - } - // Match it with a } - do - { - TK_NextToken(); - if(tk_Token == TK_EOF) - { - ERR_Exit(ERR_EOF, YES, NULL); - } - else if (tk_Token == TK_LBRACE) - { - depth++; - } - else if (tk_Token == TK_RBRACE) - { - depth--; - } - } while (depth > 0); -} + +//************************************************************************** +//** +//** parse.c +//** +//************************************************************************** + +// HEADER FILES ------------------------------------------------------------ + +#include +#include +#include +#include +#include + +#include "common.h" +#include "parse.h" +#include "symbol.h" +#include "pcode.h" +#include "token.h" +#include "error.h" +#include "misc.h" +#include "strlist.h" + +// MACROS ------------------------------------------------------------------ + +#define MAX_STATEMENT_DEPTH 128 +#define MAX_BREAK 128 +#define MAX_CONTINUE 128 +#define MAX_CASE 128 +#define EXPR_STACK_DEPTH 64 + +// TYPES ------------------------------------------------------------------- + +typedef enum +{ + STMT_SCRIPT, + STMT_IF, + STMT_ELSE, + STMT_DO, + STMT_WHILEUNTIL, + STMT_SWITCH, + STMT_FOR +} statement_t; + +typedef struct +{ + int level; + int addressPtr; +} breakInfo_t; + +typedef struct +{ + int level; + int addressPtr; +} continueInfo_t; + +typedef struct +{ + int level; + int value; + boolean isDefault; + int address; +} caseInfo_t; + +typedef struct prefunc_s +{ + struct prefunc_s *next; + symbolNode_t *sym; + int address; + int argcount; + int line; + char *source; +} prefunc_t; + +// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- + +// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- + +// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- + +static void CountScript(int type); +static void Outside(void); +static void OuterScript(void); +static void OuterFunction(void); +static void OuterMapVar(boolean local); +static void OuterWorldVar(boolean isGlobal); +static void OuterSpecialDef(void); +static void OuterDefine(boolean force); +static void OuterInclude(void); +static void OuterImport(void); +static boolean ProcessStatement(statement_t owner); +static void LeadingCompoundStatement(statement_t owner); +static void LeadingVarDeclare(void); +static void LeadingLineSpecial(boolean executewait); +static void LeadingFunction(boolean executewait); +static void LeadingIdentifier(void); +static void BuildPrintString(void); +static void ActionOnCharRange(boolean write); +static void LeadingStrcpy(void); +static void LeadingPrint(void); +static void LeadingHudMessage(void); +static void LeadingMorphActor(void); +static void LeadingVarAssign(symbolNode_t *sym); +static pcd_t GetAssignPCD(tokenType_t token, symbolType_t symbol); +static void LeadingInternFunc(symbolNode_t *sym); +static void LeadingScriptFunc(symbolNode_t *sym); +static void LeadingSuspend(void); +static void LeadingTerminate(void); +static void LeadingRestart(void); +static void LeadingReturn(void); +static void LeadingIf(void); +static void LeadingFor(void); +static void LeadingWhileUntil(void); +static void LeadingDo(void); +static void LeadingSwitch(void); +static void LeadingCase(void); +static void LeadingDefault(void); +static void LeadingBreak(void); +static void LeadingContinue(void); +static void LeadingCreateTranslation(void); +static void LeadingIncDec(int token); +static void PushCase(int value, boolean isDefault); +static caseInfo_t *GetCaseInfo(void); +static int CaseInfoCmp(const void *a, const void *b); +static boolean DefaultInCurrent(void); +static void PushBreak(void); +static void WriteBreaks(void); +static boolean BreakAncestor(void); +static void PushContinue(void); +static void WriteContinues(int address); +static boolean ContinueAncestor(void); +static void ProcessInternFunc(symbolNode_t *sym); +static void ProcessScriptFunc(symbolNode_t *sym, boolean discardReturn); +static void EvalExpression(void); +static void ExprLevX(int level); +static void ExprLevA(void); +static void ExprFactor(void); +static void ExprTernary(void); +static void ConstExprFactor(void); +static void SendExprCommand(pcd_t pcd); +static void PushExStk(int value); +static int PopExStk(void); +static pcd_t TokenToPCD(tokenType_t token); +static pcd_t GetPushVarPCD(symbolType_t symType); +static pcd_t GetIncDecPCD(tokenType_t token, symbolType_t symbol); +static int EvalConstExpression(void); +static void ParseArrayDims(int *size, int *ndim, int dims[MAX_ARRAY_DIMS]); +static void SymToArray(int symtype, symbolNode_t *sym, int index, int ndim, int size, int dims[MAX_ARRAY_DIMS]); +static void ParseArrayIndices(symbolNode_t *sym, int requiredIndices); +static void InitializeArray(symbolNode_t *sym, int dims[MAX_ARRAY_DIMS], int size); +static void InitializeScriptArray(symbolNode_t *sym, int dims[MAX_ARRAY_DIMS]); +static symbolNode_t *DemandSymbol(char *name); +static symbolNode_t *SpeculateSymbol(char *name, boolean hasReturn); +static symbolNode_t *SpeculateFunction(const char *name, boolean hasReturn); +static void UnspeculateFunction(symbolNode_t *sym); +static void AddScriptFuncRef(symbolNode_t *sym, int address, int argcount); +static void CheckForUndefinedFunctions(void); +static void SkipBraceBlock(int depth); + +// EXTERNAL DATA DECLARATIONS ---------------------------------------------- + +// PUBLIC DATA DEFINITIONS ------------------------------------------------- + +int pa_ScriptCount; +struct ScriptTypes *pa_TypedScriptCounts; +int pa_MapVarCount; +int pa_WorldVarCount; +int pa_GlobalVarCount; +int pa_WorldArrayCount; +int pa_GlobalArrayCount; +enum ImportModes ImportMode = IMPORT_None; +boolean ExporterFlagged; +boolean pa_ConstExprIsString; + +// PRIVATE DATA DEFINITIONS ------------------------------------------------ + +static int ScriptVarCount; +static int ScriptArrayCount; +static int ScriptArraySize[MAX_SCRIPT_ARRAYS]; +static statement_t StatementHistory[MAX_STATEMENT_DEPTH]; +static int StatementIndex; +static breakInfo_t BreakInfo[MAX_BREAK]; +static int BreakIndex; +static continueInfo_t ContinueInfo[MAX_CONTINUE]; +static int ContinueIndex; +static caseInfo_t CaseInfo[MAX_CASE]; +static int CaseIndex; +static int StatementLevel; +static int ExprStack[EXPR_STACK_DEPTH]; +static int ExprStackIndex; +static boolean ConstantExpression; +static symbolNode_t *InsideFunction; +static prefunc_t *FillinFunctions; +static prefunc_t **FillinFunctionsLatest = &FillinFunctions; +static boolean ArrayHasStrings; + +static int AdjustStmtLevel[] = +{ + 0, // STMT_SCRIPT + 0, // STMT_IF + 0, // STMT_ELSE + 1, // STMT_DO + 1, // STMT_WHILEUNTIL + 1, // STMT_SWITCH + 1 // STMT_FOR +}; + +static boolean IsBreakRoot[] = +{ + NO, // STMT_SCRIPT + NO, // STMT_IF + NO, // STMT_ELSE + YES, // STMT_DO + YES, // STMT_WHILEUNTIL + YES, // STMT_SWITCH + YES // STMT_FOR +}; + +static boolean IsContinueRoot[] = +{ + NO, // STMT_SCRIPT + NO, // STMT_IF + NO, // STMT_ELSE + YES, // STMT_DO + YES, // STMT_WHILEUNTIL + NO, // STMT_SWITCH + YES // STMT_FOR +}; + +static tokenType_t LevAOps[] = +{ + TK_TERNARY, + TK_NONE +}; + +static tokenType_t LevBOps[] = +{ + TK_ORLOGICAL, + TK_NONE +}; + +static tokenType_t LevCOps[] = +{ + TK_ANDLOGICAL, + TK_NONE +}; + +static tokenType_t LevDOps[] = +{ + TK_ORBITWISE, + TK_NONE +}; + +static tokenType_t LevEOps[] = +{ + TK_EORBITWISE, + TK_NONE +}; + +static tokenType_t LevFOps[] = +{ + TK_ANDBITWISE, + TK_NONE +}; + +static tokenType_t LevGOps[] = +{ + TK_EQ, + TK_NE, + TK_NONE +}; + +static tokenType_t LevHOps[] = +{ + TK_LT, + TK_LE, + TK_GT, + TK_GE, + TK_NONE +}; + +static tokenType_t LevIOps[] = +{ + TK_LSHIFT, + TK_RSHIFT, + TK_NONE +}; + +static tokenType_t LevJOps[] = +{ + TK_PLUS, + TK_MINUS, + TK_NONE +}; + +static tokenType_t LevKOps[] = +{ + TK_ASTERISK, + TK_SLASH, + TK_PERCENT, + TK_NONE +}; + +static tokenType_t *OpsList[] = +{ + LevAOps, + LevBOps, + LevCOps, + LevDOps, + LevEOps, + LevFOps, + LevGOps, + LevHOps, + LevIOps, + LevJOps, + LevKOps, + NULL +}; + +static tokenType_t AssignOps[] = +{ + TK_ASSIGN, + TK_ADDASSIGN, + TK_SUBASSIGN, + TK_MULASSIGN, + TK_DIVASSIGN, + TK_MODASSIGN, + TK_ANDASSIGN, + TK_EORASSIGN, + TK_ORASSIGN, + TK_LSASSIGN, + TK_RSASSIGN, + TK_NONE +}; + +static struct ScriptTypes ScriptCounts[] = +{ + { "closed", 0, 0 }, + { "open", OPEN_SCRIPTS_BASE, 0 }, + { "respawn", RESPAWN_SCRIPTS_BASE, 0 }, + { "death", DEATH_SCRIPTS_BASE, 0 }, + { "enter", ENTER_SCRIPTS_BASE, 0 }, + { "pickup", PICKUP_SCRIPTS_BASE, 0 }, + { "bluereturn", BLUE_RETURN_SCRIPTS_BASE, 0 }, + { "redreturn", RED_RETURN_SCRIPTS_BASE, 0 }, + { "whitereturn", WHITE_RETURN_SCRIPTS_BASE, 0 }, + { "lightning", LIGHTNING_SCRIPTS_BASE, 0 }, + { "disconnect", DISCONNECT_SCRIPTS_BASE, 0 }, + { "unloading", UNLOADING_SCRIPTS_BASE, 0 }, + { "return", RETURN_SCRIPTS_BASE, 0 }, + { "event", EVENT_SCRIPTS_BASE, 0 }, + { "kill", KILL_SCRIPTS_BASE, 0 }, + { "reopen", REOPEN_SCRIPTS_BASE, 0 }, + { NULL, -1, 0 } +}; + +// CODE -------------------------------------------------------------------- + +//========================================================================== +// +// PA_Parse +// +//========================================================================== + +void PA_Parse(void) +{ + int i; + + pa_ScriptCount = 0; + pa_TypedScriptCounts = ScriptCounts; + for (i = 0; ScriptCounts[i].TypeName != NULL; i++) + { + ScriptCounts[i].TypeCount = 0; + } + pa_MapVarCount = 0; + pa_WorldVarCount = 0; + pa_GlobalVarCount = 0; + pa_WorldArrayCount = 0; + pa_GlobalArrayCount = 0; + TK_NextToken(); + Outside(); + CheckForUndefinedFunctions(); + ERR_Finish(); +} + +//========================================================================== +// +// CountScript +// +//========================================================================== + +static void CountScript(int type) +{ + int i; + + for (i = 0; ScriptCounts[i].TypeName != NULL; i++) + { + if (ScriptCounts[i].TypeBase == type) + { + if (type != 0) + { + MS_Message(MSG_DEBUG, "Script type: %s\n", + ScriptCounts[i].TypeName); + } + ScriptCounts[i].TypeCount++; + return; + } + } + return; +} + +//========================================================================== +// +// Outside +// +//========================================================================== + +static void Outside(void) +{ + boolean done; + int outertokencount; + + done = NO; + outertokencount = 0; + while(done == NO) + { + outertokencount++; + switch(tk_Token) + { + case TK_EOF: + done = YES; + break; + case TK_SCRIPT: + OuterScript(); + break; + case TK_FUNCTION: + OuterFunction(); + break; + case TK_INT: + case TK_STR: + case TK_BOOL: + OuterMapVar(NO); + break; + case TK_WORLD: + OuterWorldVar(NO); + break; + case TK_GLOBAL: + OuterWorldVar(YES); + break; + case TK_SPECIAL: + OuterSpecialDef(); + break; + case TK_NUMBERSIGN: + TK_NextToken(); + switch(tk_Token) + { + case TK_DEFINE: + OuterDefine(NO); + break; + case TK_LIBDEFINE: + OuterDefine(YES); + break; + case TK_INCLUDE: + OuterInclude(); + break; + case TK_NOCOMPACT: + if(ImportMode != IMPORT_Importing) + { + if(pc_Address != 8) + { + ERR_Error(ERR_NOCOMPACT_NOT_HERE, YES); + } + MS_Message(MSG_DEBUG, "Forcing NoShrink\n"); + pc_NoShrink = TRUE; + } + TK_NextToken(); + break; + case TK_WADAUTHOR: + if(ImportMode != IMPORT_Importing) + { + MS_Message(MSG_DEBUG, "Will write WadAuthor-compatible object\n"); + MS_Message(MSG_NORMAL, "You don't need to use #wadauthor anymore.\n"); + pc_WadAuthor = TRUE; + } + TK_NextToken(); + break; + case TK_NOWADAUTHOR: + if(ImportMode != IMPORT_Importing) + { + MS_Message(MSG_DEBUG, "Will write WadAuthor-incompatible object\n"); + pc_WadAuthor = FALSE; + } + TK_NextToken(); + break; + case TK_ENCRYPTSTRINGS: + if(ImportMode != IMPORT_Importing) + { + MS_Message(MSG_DEBUG, "Strings will be encrypted\n"); + pc_EncryptStrings = TRUE; + if(pc_EnforceHexen) + { + ERR_Error(ERR_HEXEN_COMPAT, YES); + } + } + TK_NextToken(); + break; + case TK_IMPORT: + OuterImport(); + outertokencount = 0; + break; + case TK_LIBRARY: + if (outertokencount != 1) + { + ERR_Error(ERR_LIBRARY_NOT_FIRST, YES); + } + TK_NextTokenMustBe(TK_STRING, ERR_STRING_LIT_NOT_FOUND); + if(ImportMode == IMPORT_None) + { + MS_Message(MSG_DEBUG, "Allocations modified for exporting\n"); + ImportMode = IMPORT_Exporting; + if(pc_EnforceHexen) + { + ERR_Error(ERR_HEXEN_COMPAT, YES); + } + } + else if(ImportMode == IMPORT_Importing) + { + PC_AddImport(tk_String); + ExporterFlagged = YES; + } + TK_NextToken(); + break; + case TK_REGION: // [mxd] + case TK_ENDREGION: + outertokencount--; // #region markers should not count as "real" tokens + TK_SkipLine(); + break; + default: + ERR_Error(ERR_INVALID_DIRECTIVE, YES); + TK_SkipLine(); + break; + } + break; + default: + ERR_Exit(ERR_INVALID_DECLARATOR, YES, NULL); + break; + } + } +} + +//========================================================================== +// +// OuterScript +// +//========================================================================== + +static void OuterScript(void) +{ + int scriptNumber; + symbolNode_t *sym; + int scriptType, scriptFlags; + + MS_Message(MSG_DEBUG, "---- OuterScript ----\n"); + BreakIndex = 0; + CaseIndex = 0; + StatementLevel = 0; + ScriptVarCount = 0; + ScriptArrayCount = 0; + SY_FreeLocals(); + TK_NextToken(); + + if(ImportMode == IMPORT_Importing) + { + // When importing, the script number is not recorded, because + // it might be a #define that is not included by the main .acs + // file, so processing it would generate a syntax error. + SkipBraceBlock(0); + TK_NextToken(); + return; + } + + // [RH] If you want to use script 0, it must be written as <<0>>. + // This is to avoid using it accidentally, since ZDoom uses script + // 0 to implement many of the Strife-specific line specials. + + if(tk_Token == TK_LSHIFT) + { + TK_NextTokenMustBe(TK_NUMBER, ERR_SCRIPT_OUT_OF_RANGE); + if(tk_Number != 0) + { + ERR_Exit(ERR_SCRIPT_OUT_OF_RANGE, YES, NULL); + } + TK_NextTokenMustBe(TK_RSHIFT, ERR_SCRIPT_OUT_OF_RANGE); + TK_NextToken(); + scriptNumber = 0; + } + else if(tk_Token == TK_STRING) + { // Named scripts start counting at -1 and go down from there. + if(strcasecmp("None", tk_String) == 0) + { + ERR_Error(ERR_SCRIPT_NAMED_NONE, YES, NULL); + } + scriptNumber = -1 - STR_FindInListInsensitive(STRLIST_NAMEDSCRIPTS, tk_String); + TK_NextToken(); + } + else + { + scriptNumber = EvalConstExpression(); + if(scriptNumber < 1 || scriptNumber > 32767) + { + TK_Undo(); + ERR_Error(ERR_SCRIPT_OUT_OF_RANGE, YES, NULL); + SkipBraceBlock(0); + TK_NextToken(); + return; + } + } + if (scriptNumber >= 0) + { + MS_Message(MSG_DEBUG, "Script number: %d\n", scriptNumber); + } + else + { + MS_Message(MSG_DEBUG, "Script name: %s (%d)\n", + STR_GetString(STRLIST_NAMEDSCRIPTS, -scriptNumber - 1), + scriptNumber); + } + scriptType = 0; + scriptFlags = 0; + if(tk_Token == TK_LPAREN) + { + if(TK_NextToken() == TK_VOID) + { + TK_NextTokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN); + } + else + { + TK_Undo(); + do + { + TK_NextTokenMustBe(TK_INT, ERR_BAD_VAR_TYPE); + TK_NextTokenMustBe(TK_IDENTIFIER, ERR_INVALID_IDENTIFIER); + if(ScriptVarCount == 4) + { + ERR_Error(ERR_TOO_MANY_SCRIPT_ARGS, YES); + } + if(SY_FindLocal(tk_String) != NULL) + { // Redefined + ERR_Error(ERR_REDEFINED_IDENTIFIER, YES, tk_String); + } + else if(ScriptVarCount < 4) + { + sym = SY_InsertLocal(tk_String, SY_SCRIPTVAR); + sym->info.var.index = ScriptVarCount; + ScriptVarCount++; + } + TK_NextToken(); + } while(tk_Token == TK_COMMA); + TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN); + } + TK_NextToken(); + switch(tk_Token) + { + case TK_DISCONNECT: + scriptType = DISCONNECT_SCRIPTS_BASE; + if(ScriptVarCount != 1) + { + ERR_Error(ERR_DISCONNECT_NEEDS_1_ARG, YES); + } + break; + + case TK_OPEN: + case TK_RESPAWN: + case TK_DEATH: + case TK_ENTER: + case TK_PICKUP: + case TK_BLUERETURN: + case TK_REDRETURN: + case TK_WHITERETURN: + case TK_LIGHTNING: + case TK_UNLOADING: + case TK_RETURN: + case TK_KILL: + case TK_REOPEN: + ERR_Error(ERR_UNCLOSED_WITH_ARGS, YES); + break; + + case TK_EVENT: + scriptType = EVENT_SCRIPTS_BASE; + if(ScriptVarCount != 3) + { + ERR_Error(ERR_EVENT_NEEDS_3_ARG, YES); + } + break; + + default: + TK_Undo(); + } + MS_Message(MSG_DEBUG, "Script type: %s (%d %s)\n", + scriptType == 0 ? "closed" : "disconnect", + ScriptVarCount, ScriptVarCount == 1 ? "arg" : "args"); + } + else switch (tk_Token) + { + case TK_OPEN: + scriptType = OPEN_SCRIPTS_BASE; + break; + + case TK_RESPAWN: // [BC] + scriptType = RESPAWN_SCRIPTS_BASE; + break; + + case TK_DEATH: // [BC] + scriptType = DEATH_SCRIPTS_BASE; + break; + + case TK_ENTER: // [BC] + scriptType = ENTER_SCRIPTS_BASE; + break; + + case TK_RETURN: + scriptType = RETURN_SCRIPTS_BASE; + break; + + case TK_PICKUP: // [BC] + scriptType = PICKUP_SCRIPTS_BASE; + break; + + case TK_BLUERETURN: // [BC] + scriptType = BLUE_RETURN_SCRIPTS_BASE; + break; + + case TK_REDRETURN: // [BC] + scriptType = RED_RETURN_SCRIPTS_BASE; + break; + + case TK_WHITERETURN: // [BC] + scriptType = WHITE_RETURN_SCRIPTS_BASE; + break; + + case TK_LIGHTNING: + scriptType = LIGHTNING_SCRIPTS_BASE; + break; + + case TK_UNLOADING: + scriptType = UNLOADING_SCRIPTS_BASE; + break; + + case TK_DISCONNECT: + scriptType = DISCONNECT_SCRIPTS_BASE; + ERR_Error (ERR_DISCONNECT_NEEDS_1_ARG, YES); + break; + + case TK_EVENT: // [BB] + scriptType = EVENT_SCRIPTS_BASE; + ERR_Error (ERR_EVENT_NEEDS_3_ARG, YES); + break; + + case TK_KILL: // [JM] + scriptType = KILL_SCRIPTS_BASE; + break; + + case TK_REOPEN: // [Nash] + scriptType = REOPEN_SCRIPTS_BASE; + break; + + default: + ERR_Error(ERR_BAD_SCRIPT_DECL, YES); + SkipBraceBlock(0); + TK_NextToken(); + return; + } + TK_NextToken(); + if(tk_Token == TK_NET) + { + scriptFlags |= NET_SCRIPT_FLAG; + TK_NextToken(); + } + // [BB] If NET and CLIENTSIDE are specified, this construction can only parse + // "NET CLIENTSIDE" but not "CLIENTSIDE NET". + if(tk_Token == TK_CLIENTSIDE) + { + scriptFlags |= CLIENTSIDE_SCRIPT_FLAG; + TK_NextToken(); + } + CountScript(scriptType); + PC_AddScript(scriptNumber, scriptType, scriptFlags, ScriptVarCount); + pc_LastAppendedCommand = PCD_NOP; + if(ProcessStatement(STMT_SCRIPT) == NO) + { + ERR_Error(ERR_INVALID_STATEMENT, YES); + } + if(pc_LastAppendedCommand != PCD_TERMINATE) + { + PC_AppendCmd(PCD_TERMINATE); + } + PC_SetScriptVarCount(scriptNumber, scriptType, ScriptVarCount, ScriptArrayCount, ScriptArraySize); + pa_ScriptCount++; +} + +//========================================================================== +// +// OuterFunction +// +//========================================================================== + +static void OuterFunction(void) +{ + enum ImportModes importing; + boolean hasReturn; + symbolNode_t *sym; + int defLine; + + MS_Message(MSG_DEBUG, "---- OuterFunction ----\n"); + importing = ImportMode; + BreakIndex = 0; + CaseIndex = 0; + StatementLevel = 0; + ScriptVarCount = 0; + ScriptArrayCount = 0; + SY_FreeLocals(); + TK_NextToken(); + if(tk_Token != TK_STR && tk_Token != TK_INT && + tk_Token != TK_VOID && tk_Token != TK_BOOL) + { + ERR_Error(ERR_BAD_RETURN_TYPE, YES); + tk_Token = TK_VOID; + } + hasReturn = tk_Token != TK_VOID; + TK_NextTokenMustBe(TK_IDENTIFIER, ERR_INVALID_IDENTIFIER); + sym = SY_FindGlobal(tk_String); + if(sym != NULL) + { + if(sym->type != SY_SCRIPTFUNC) + { // Redefined + ERR_Error(ERR_REDEFINED_IDENTIFIER, YES, tk_String); + SkipBraceBlock(0); + TK_NextToken(); + return; + } + if(!sym->info.scriptFunc.predefined) + { + ERR_Error(ERR_FUNCTION_ALREADY_DEFINED, YES); + ERR_ErrorAt(sym->info.scriptFunc.sourceName, sym->info.scriptFunc.sourceLine); + ERR_Error(ERR_NONE, YES, "Previous definition was here."); + SkipBraceBlock(0); + TK_NextToken(); + return; + } + if(sym->info.scriptFunc.hasReturnValue && !hasReturn) + { + ERR_Error(ERR_PREVIOUS_NOT_VOID, YES); + ERR_ErrorAt(sym->info.scriptFunc.sourceName, sym->info.scriptFunc.sourceLine); + ERR_Error(ERR_NONE, YES, "Previous use was here."); + } + } + else + { + sym = SY_InsertGlobal(tk_String, SY_SCRIPTFUNC); + if (importing == IMPORT_Importing) + { + sym->info.scriptFunc.address = 0; + sym->info.scriptFunc.predefined = NO; + } + else + { + sym->info.scriptFunc.address = pc_Address; + sym->info.scriptFunc.predefined = YES; + // only for consistency with other speculated functions and pretty logs + sym->info.scriptFunc.funcNumber = 0; + } + } + defLine = tk_Line; + + TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN); + if(TK_NextToken() == TK_VOID) + { + TK_NextTokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN); + } + else + { + TK_Undo(); + do + { + symbolType_t type; + symbolNode_t *local; + + TK_NextToken(); +/* if(tk_Token != TK_INT && tk_Token != TK_STR && tk_Token != TK_BOOL) + { + ERR_Error(ERR_BAD_VAR_TYPE, YES); + tk_Token = TK_INT; + } +*/ if(tk_Token == TK_INT || tk_Token == TK_BOOL) + { + if(TK_NextToken() == TK_LBRACKET) + { + TK_NextTokenMustBe(TK_RBRACKET, ERR_BAD_VAR_TYPE); + type = SY_SCRIPTALIAS; + } + else + { + TK_Undo(); + type = SY_SCRIPTVAR; + } + } + else if(tk_Token == TK_STR) + { + type = SY_SCRIPTVAR; + } + else + { + type = SY_SCRIPTVAR; + ERR_Error(ERR_BAD_VAR_TYPE, YES); + tk_Token = TK_INT; + } + TK_NextTokenMustBe(TK_IDENTIFIER, ERR_INVALID_IDENTIFIER); + if(SY_FindLocal(tk_String) != NULL) + { // Redefined + ERR_Error(ERR_REDEFINED_IDENTIFIER, YES, tk_String); + } + else + { + local = SY_InsertLocal(tk_String, type); + local->info.var.index = ScriptVarCount; + ScriptVarCount++; + } + TK_NextToken(); + } while(tk_Token == TK_COMMA); + TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN); + } + if(pc_EnforceHexen) + { + ERR_Error(ERR_HEXEN_COMPAT, YES); + } + + sym->info.scriptFunc.sourceLine = defLine; + sym->info.scriptFunc.sourceName = tk_SourceName; + sym->info.scriptFunc.argCount = ScriptVarCount; + sym->info.scriptFunc.address = (importing == IMPORT_Importing) ? 0 : pc_Address; + sym->info.scriptFunc.hasReturnValue = hasReturn; + + if(importing == IMPORT_Importing) + { + SkipBraceBlock(0); + TK_NextToken(); + sym->info.scriptFunc.predefined = NO; + sym->info.scriptFunc.varCount = ScriptVarCount; + return; + } + + TK_NextToken(); + InsideFunction = sym; + pc_LastAppendedCommand = PCD_NOP; + + // If we just call ProcessStatement(STMT_SCRIPT), and this function + // needs to return a value but the last pcode output was not a return, + // then the line number given in the error can be confusing because it + // is beyond the end of the function. To avoid this, we process the + // compound statement ourself and check if it returned something + // before checking for the '}'. If a return is required, then the error + // line will be shown as the one that contains the '}' (if present). + + TK_TokenMustBe(TK_LBRACE, ERR_MISSING_LBRACE); + TK_NextToken(); + do {} while(ProcessStatement(STMT_SCRIPT) == YES); + + if(pc_LastAppendedCommand != PCD_RETURNVOID && + pc_LastAppendedCommand != PCD_RETURNVAL) + { + if(hasReturn) + { + TK_Undo(); + ERR_Error(ERR_MUST_RETURN_A_VALUE, YES, NULL); + } + PC_AppendCmd(PCD_RETURNVOID); + } + + TK_TokenMustBe(TK_RBRACE, ERR_INVALID_STATEMENT); + TK_NextToken(); + + sym->info.scriptFunc.predefined = NO; + sym->info.scriptFunc.varCount = ScriptVarCount - + sym->info.scriptFunc.argCount; + PC_AddFunction(sym, ScriptArrayCount, ScriptArraySize); + UnspeculateFunction(sym); + InsideFunction = NULL; +} + +//========================================================================== +// +// OuterMapVar +// +//========================================================================== + +static void OuterMapVar(boolean local) +{ + symbolNode_t *sym = NULL; + int index; + + MS_Message(MSG_DEBUG, "---- %s ----\n", local ? "LeadingStaticVarDeclare" : "OuterMapVar"); + do + { + if(pa_MapVarCount >= MAX_MAP_VARIABLES) + { + ERR_Error(ERR_TOO_MANY_MAP_VARS, YES); + index = MAX_MAP_VARIABLES; + } + TK_NextTokenMustBe(TK_IDENTIFIER, ERR_INVALID_IDENTIFIER); + sym = local ? SY_FindLocal(tk_String) + : SY_FindGlobal(tk_String); + if(sym != NULL) + { // Redefined + ERR_Error(ERR_REDEFINED_IDENTIFIER, YES, tk_String); + index = MAX_MAP_VARIABLES; + } + else + { + sym = local ? SY_InsertLocal(tk_String, SY_MAPVAR) + : SY_InsertGlobal(tk_String, SY_MAPVAR); + if(ImportMode == IMPORT_Importing) + { + sym->info.var.index = index = 0; + } + else + { + sym->info.var.index = index = pa_MapVarCount; + if (!local) + { // Local variables are not exported + PC_NameMapVariable(index, sym); + } + pa_MapVarCount++; + } + } + TK_NextToken(); + if(tk_Token == TK_ASSIGN) + { + if(ImportMode != IMPORT_Importing) + { + TK_NextToken(); + PC_PutMapVariable (index, EvalConstExpression()); + } + else + { + // When importing, skip the initializer, because we don't care. + do + { + TK_NextToken(); + } while(tk_Token != TK_COMMA && tk_Token != TK_SEMICOLON); + } + } + else if(tk_Token == TK_LBRACKET) + { + int size, ndim, dims[MAX_ARRAY_DIMS]; + + ParseArrayDims(&size, &ndim, dims); + + if(sym != NULL) + { + if(ImportMode != IMPORT_Importing) + { + PC_AddArray(index, size); + } + SymToArray(SY_MAPARRAY, sym, index, size, ndim, dims); + if(tk_Token == TK_ASSIGN) + { + InitializeArray(sym, dims, size); + } + } + } + } while(tk_Token == TK_COMMA); + TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON); + TK_NextToken(); +} + +//========================================================================== +// +// OuterWorldVar +// +//========================================================================== + +static void OuterWorldVar(boolean isGlobal) +{ + int index; + symbolNode_t *sym; + + MS_Message(MSG_DEBUG, "---- Outer%sVar ----\n", isGlobal ? "Global" : "World"); + if(TK_NextToken() != TK_INT) + { + if(tk_Token != TK_BOOL) + { + TK_TokenMustBe(TK_STR, ERR_BAD_VAR_TYPE); + } + } + do + { + TK_NextTokenMustBe(TK_NUMBER, ERR_MISSING_WVAR_INDEX); + if(tk_Number >= (isGlobal ? MAX_GLOBAL_VARIABLES : MAX_WORLD_VARIABLES)) + { + ERR_Error(ERR_BAD_WVAR_INDEX+isGlobal, YES); + index = 0; + } + else + { + index = tk_Number; + } + TK_NextTokenMustBe(TK_COLON, ERR_MISSING_WVAR_COLON+isGlobal); + TK_NextTokenMustBe(TK_IDENTIFIER, ERR_INVALID_IDENTIFIER); + if(SY_FindGlobal(tk_String) != NULL) + { // Redefined + ERR_Error(ERR_REDEFINED_IDENTIFIER, YES, tk_String); + } + else + { + TK_NextToken(); + if(tk_Token == TK_LBRACKET) + { + TK_NextToken (); + if(tk_Token != TK_RBRACKET) + { + ERR_Error(ERR_NO_NEED_ARRAY_SIZE, YES); + TK_SkipPast(TK_RBRACKET); + } + else + { + TK_NextToken(); + } + if(tk_Token == TK_LBRACKET) + { + ERR_Error(ERR_NO_MULTIDIMENSIONS, YES); + do + { + TK_SkipPast(TK_RBRACKET); + } + while(tk_Token == TK_LBRACKET); + } + sym = SY_InsertGlobal(tk_String, isGlobal ? SY_GLOBALARRAY : SY_WORLDARRAY); + sym->info.array.index = index; + sym->info.array.ndim = 1; + sym->info.array.size = 0x7fffffff; // not used + memset(sym->info.array.dimensions, 0, sizeof(sym->info.array.dimensions)); + + if (isGlobal) + pa_GlobalArrayCount++; + else + pa_WorldArrayCount++; + } + else + { + sym = SY_InsertGlobal(tk_String, isGlobal ? SY_GLOBALVAR : SY_WORLDVAR); + sym->info.var.index = index; + if (isGlobal) + pa_GlobalVarCount++; + else + pa_WorldVarCount++; + } + } + } while(tk_Token == TK_COMMA); + TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON); + TK_NextToken(); +} + +//========================================================================== +// +// OuterSpecialDef +// +//========================================================================== + +static void OuterSpecialDef(void) +{ + int special; + symbolNode_t *sym; + + MS_Message(MSG_DEBUG, "---- OuterSpecialDef ----\n"); + if(ImportMode == IMPORT_Importing) + { + // No need to process special definitions when importing. + TK_SkipPast(TK_SEMICOLON); + } + else + { + do + { + if (TK_NextToken() == TK_MINUS) + { + TK_NextTokenMustBe(TK_NUMBER, ERR_MISSING_SPEC_VAL); + special = -tk_Number; + } + else + { + TK_TokenMustBe(TK_NUMBER, ERR_MISSING_SPEC_VAL); + special = tk_Number; + } + TK_NextTokenMustBe(TK_COLON, ERR_MISSING_SPEC_COLON); + TK_NextTokenMustBe(TK_IDENTIFIER, ERR_INVALID_IDENTIFIER); + sym = SY_InsertGlobalUnique(tk_String, SY_SPECIAL); + TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN); + TK_NextTokenMustBe(TK_NUMBER, ERR_MISSING_SPEC_ARGC); + sym->info.special.value = special; + sym->info.special.argCount = tk_Number | (tk_Number << 16); + TK_NextToken(); + if(tk_Token == TK_COMMA) + { // Get maximum arg count + TK_NextTokenMustBe(TK_NUMBER, ERR_MISSING_SPEC_ARGC); + sym->info.special.argCount = + (sym->info.special.argCount & 0xffff) | (tk_Number << 16); + } + else + { + TK_Undo (); + } + TK_NextTokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN); + TK_NextToken(); + } while(tk_Token == TK_COMMA); + TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON); + TK_NextToken(); + } +} + +//========================================================================== +// +// OuterDefine +// +//========================================================================== + +static void OuterDefine(boolean force) +{ + int value; + symbolNode_t *sym; + + MS_Message(MSG_DEBUG, "---- OuterDefine %s----\n", + force ? "(forced) " : ""); + TK_NextTokenMustBe(TK_IDENTIFIER, ERR_INVALID_IDENTIFIER); + sym = SY_InsertGlobalUnique(tk_String, SY_CONSTANT); + // Defines inside an import are deleted when the import is popped. + if(ImportMode != IMPORT_Importing || force) + { + sym->info.constant.fileDepth = 0; + } + else + { + sym->info.constant.fileDepth = TK_GetDepth(); + } + + TK_NextToken(); + value = EvalConstExpression(); + MS_Message(MSG_DEBUG, "Constant value: %d\n", value); + sym->info.constant.value = value; + sym->info.constant.strValue = pa_ConstExprIsString ? strdup(STR_Get(value)) : NULL; +} + +//========================================================================== +// +// OuterInclude +// +//========================================================================== + +static void OuterInclude(void) +{ + // Don't include inside an import + if(ImportMode != IMPORT_Importing) + { + MS_Message(MSG_DEBUG, "---- OuterInclude ----\n"); + TK_NextTokenMustBe(TK_STRING, ERR_STRING_LIT_NOT_FOUND); + TK_Include(tk_String); + } + else + { + TK_NextToken(); + } + TK_NextToken(); +} + +//========================================================================== +// +// OuterImport +// +//========================================================================== + +static void OuterImport(void) +{ + + MS_Message(MSG_DEBUG, "---- OuterImport ----\n"); + if(ImportMode == IMPORT_Importing) + { + // Don't import inside an import + TK_NextToken(); + } + else + { + MS_Message(MSG_DEBUG, "Importing a file\n"); + TK_NextTokenMustBe(TK_STRING, ERR_STRING_LIT_NOT_FOUND); + TK_Import(tk_String, ImportMode); + } + TK_NextToken(); +} + +//========================================================================== +// +// ProcessStatement +// +//========================================================================== + +static boolean ProcessStatement(statement_t owner) +{ + if(StatementIndex == MAX_STATEMENT_DEPTH) + { + ERR_Exit(ERR_STATEMENT_OVERFLOW, YES); + } + StatementHistory[StatementIndex++] = owner; + StatementLevel += AdjustStmtLevel[owner]; + switch(tk_Token) + { + case TK_INT: + case TK_STR: + case TK_BOOL: + case TK_STATIC: + LeadingVarDeclare(); + break; + case TK_LINESPECIAL: + if (tk_SpecialValue >= 0) + { + LeadingLineSpecial(NO); + } + else + { + LeadingFunction(NO); + } + break; + case TK_ACSEXECUTEWAIT: + if(InsideFunction) + { + ERR_Error(ERR_LATENT_IN_FUNC, YES); + } + tk_SpecialArgCount = 1 | (5<<16); + tk_SpecialValue = 80; + LeadingLineSpecial(YES); + break; + case TK_ACSNAMEDEXECUTEWAIT: + if(InsideFunction) + { + ERR_Error(ERR_LATENT_IN_FUNC, YES); + } + tk_SpecialArgCount = 1 | (5<<16); + tk_SpecialValue = -39; + LeadingFunction(YES); + break; + case TK_RESTART: + LeadingRestart(); + break; + case TK_SUSPEND: + LeadingSuspend(); + break; + case TK_TERMINATE: + LeadingTerminate(); + break; + case TK_RETURN: + LeadingReturn(); + break; + case TK_IDENTIFIER: + LeadingIdentifier(); + break; + case TK_PRINT: + case TK_PRINTBOLD: + case TK_LOG: + LeadingPrint(); + break; + + case TK_STRPARAM_EVAL: + LeadingPrint(); + PC_AppendCmd(PCD_DROP); + /* Duplicate code: LeadingPrint() post-processing: */ + TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON); + TK_NextToken(); + break; + + case TK_STRCPY: + LeadingStrcpy(); + PC_AppendCmd(PCD_DROP); + TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON); + TK_NextToken(); + break; + + case TK_HUDMESSAGE: + case TK_HUDMESSAGEBOLD: + LeadingHudMessage(); + break; + case TK_MORPHACTOR: + LeadingMorphActor(); + PC_AppendCmd(PCD_DROP); + TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON); + TK_NextToken(); + break; + case TK_IF: + LeadingIf(); + break; + case TK_FOR: + LeadingFor(); + break; + case TK_WHILE: + case TK_UNTIL: + LeadingWhileUntil(); + break; + case TK_DO: + LeadingDo(); + break; + case TK_SWITCH: + LeadingSwitch(); + break; + case TK_CASE: + if(owner != STMT_SWITCH) + { + ERR_Error(ERR_CASE_NOT_IN_SWITCH, YES); + TK_SkipPast(TK_COLON); + } + else + { + LeadingCase(); + } + break; + case TK_DEFAULT: + if(owner != STMT_SWITCH) + { + ERR_Error(ERR_DEFAULT_NOT_IN_SWITCH, YES); + TK_SkipPast(TK_COLON); + } + else if(DefaultInCurrent() == YES) + { + ERR_Error(ERR_MULTIPLE_DEFAULT, YES); + TK_SkipPast(TK_COLON); + } + else + { + LeadingDefault(); + } + break; + case TK_BREAK: + if(BreakAncestor() == NO) + { + ERR_Error(ERR_MISPLACED_BREAK, YES); + TK_SkipPast(TK_SEMICOLON); + } + else + { + LeadingBreak(); + } + break; + case TK_CONTINUE: + if(ContinueAncestor() == NO) + { + ERR_Error(ERR_MISPLACED_CONTINUE, YES); + TK_SkipPast(TK_SEMICOLON); + } + else + { + LeadingContinue(); + } + break; + case TK_CREATETRANSLATION: + LeadingCreateTranslation(); + break; + case TK_LBRACE: + LeadingCompoundStatement(owner); + break; + case TK_SEMICOLON: + TK_NextToken(); + break; + case TK_INC: + case TK_DEC: + LeadingIncDec(tk_Token); + break; + + default: + StatementIndex--; + StatementLevel -= AdjustStmtLevel[owner]; + return NO; + break; + } + StatementIndex--; + StatementLevel -= AdjustStmtLevel[owner]; + return YES; +} + +//========================================================================== +// +// LeadingCompoundStatement +// +//========================================================================== + +static void LeadingCompoundStatement(statement_t owner) +{ + //StatementLevel += AdjustStmtLevel[owner]; + TK_NextToken(); // Eat the TK_LBRACE + do {} while(ProcessStatement(owner) == YES); + TK_TokenMustBe(TK_RBRACE, ERR_INVALID_STATEMENT); + TK_NextToken(); + //StatementLevel -= AdjustStmtLevel[owner]; +} + +//========================================================================== +// +// LeadingVarDeclare +// +//========================================================================== + +static void LeadingVarDeclare(void) +{ + symbolNode_t *sym = NULL; + + if(tk_Token == TK_STATIC) + { + TK_NextToken(); + if(tk_Token != TK_INT && tk_Token != TK_STR && tk_Token != TK_BOOL) + { + ERR_Error(ERR_BAD_VAR_TYPE, YES); + TK_Undo(); + } + OuterMapVar(YES); + return; + } + + MS_Message(MSG_DEBUG, "---- LeadingVarDeclare ----\n"); + do + { + TK_NextTokenMustBe(TK_IDENTIFIER, ERR_INVALID_IDENTIFIER); +#if 0 + if(ScriptVarCount == MAX_SCRIPT_VARIABLES) + { + ERR_Error(InsideFunction + ? ERR_TOO_MANY_FUNCTION_VARS + : ERR_TOO_MANY_SCRIPT_VARS, + YES, NULL); + ScriptVarCount++; + } + else +#endif + if(SY_FindLocal(tk_String) != NULL) + { // Redefined + ERR_Error(ERR_REDEFINED_IDENTIFIER, YES, tk_String); + } + else + { + sym = SY_InsertLocal(tk_String, SY_SCRIPTVAR); + sym->info.var.index = ScriptVarCount; + ScriptVarCount++; + } + TK_NextToken(); + if(tk_Token == TK_LBRACKET) + { + int size, ndim, dims[MAX_ARRAY_DIMS]; + + ParseArrayDims(&size, &ndim, dims); + if(sym != NULL) + { + ScriptVarCount--; + if(ScriptArrayCount == MAX_SCRIPT_ARRAYS) + { + ERR_Error(InsideFunction ? ERR_TOO_MANY_FUNCTION_ARRAYS : ERR_TOO_MANY_SCRIPT_ARRAYS, YES, NULL); + } + if(ScriptArrayCount < MAX_SCRIPT_ARRAYS) + { + ScriptArraySize[ScriptArrayCount] = size; + } + SymToArray(SY_SCRIPTARRAY, sym, ScriptArrayCount++, size, ndim, dims); + if(tk_Token == TK_ASSIGN) + { + InitializeScriptArray(sym, dims); + } + } + } + else if(tk_Token == TK_ASSIGN) + { + TK_NextToken(); + EvalExpression(); + if(sym != NULL) + { + PC_AppendCmd(PCD_ASSIGNSCRIPTVAR); + PC_AppendShrink(sym->info.var.index); + } + } + } while(tk_Token == TK_COMMA); + TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON); + TK_NextToken(); +} + +//========================================================================== +// +// LeadingLineSpecial +// +//========================================================================== + +static void LeadingLineSpecial(boolean executewait) +{ + int i; + int argCount; + int argCountMin; + int argCountMax; + int argSave[8]; + U_INT specialValue; + boolean direct; + + MS_Message(MSG_DEBUG, "---- LeadingLineSpecial ----\n"); + argCountMin = tk_SpecialArgCount & 0xffff; + argCountMax = tk_SpecialArgCount >> 16; + specialValue = tk_SpecialValue; + TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN); + i = 0; + if(argCountMax > 0) + { + if(TK_NextToken() == TK_CONST) + { + TK_NextTokenMustBe(TK_COLON, ERR_MISSING_COLON); + direct = YES; + } + else + { + TK_Undo(); + direct = NO; + } + do + { + if(i == argCountMax) + { + ERR_Error(ERR_BAD_LSPEC_ARG_COUNT, YES); + i = argCountMax+1; + } + TK_NextToken(); + if(direct == YES) + { + argSave[i] = EvalConstExpression(); + } + else + { + EvalExpression(); + if (i == 0 && executewait) + { + PC_AppendCmd(PCD_DUP); + } + } + if(i < argCountMax) + { + i++; + } + } while(tk_Token == TK_COMMA); + if(i < argCountMin) + { + ERR_Error(ERR_BAD_LSPEC_ARG_COUNT, YES); + TK_SkipPast(TK_SEMICOLON); + return; + } + argCount = i; + } + else + { + // [RH] I added some zero-argument specials without realizing that + // ACS won't allow for less than one, so fake them as one-argument + // specials with a parameter of 0. + argCount = 1; + direct = YES; + argSave[0] = 0; + TK_NextToken (); + } + TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN); + TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON); + if (specialValue > 255) + { + for(; argCount < 5; ++argCount) + { + PC_AppendPushVal(0); + } + PC_AppendCmd(PCD_LSPEC5EX); + PC_AppendInt(specialValue); + if(executewait) + { + PC_AppendCmd(PCD_SCRIPTWAITDIRECT); + PC_AppendInt(argSave[0]); + } + } + else if(direct == NO) + { + PC_AppendCmd(PCD_LSPEC1+(argCount-1)); + if(pc_NoShrink) + { + PC_AppendInt(specialValue); + } + else + { + if (specialValue > 255) + { + ERR_Error(ERR_SPECIAL_RANGE, YES); + } + PC_AppendByte((U_BYTE)specialValue); + } + if(executewait) + { + PC_AppendCmd(PCD_SCRIPTWAIT); + } + } + else + { + boolean useintform; + + if(pc_NoShrink) + { + PC_AppendCmd(PCD_LSPEC1DIRECT+(argCount-1)); + PC_AppendInt(specialValue); + useintform = YES; + } + else + { + useintform = NO; + for (i = 0; i < argCount; i++) + { + if ((U_INT)argSave[i] > 255) + { + useintform = YES; + break; + } + } + PC_AppendCmd((argCount-1)+(useintform?PCD_LSPEC1DIRECT:PCD_LSPEC1DIRECTB)); + PC_AppendByte((U_BYTE)specialValue); + } + if (useintform) + { + for (i = 0; i < argCount; i++) + { + PC_AppendInt(argSave[i]); + } + } + else + { + for (i = 0; i < argCount; i++) + { + PC_AppendByte((U_BYTE)argSave[i]); + } + } + if(executewait) + { + PC_AppendCmd(PCD_SCRIPTWAITDIRECT); + PC_AppendInt(argSave[0]); + } + } + TK_NextToken(); +} + +//========================================================================== +// +// LeadingFunction +// +//========================================================================== + +static void LeadingFunction(boolean executewait) +{ + int i; + int argCount; + int argCountMin; + int argCountMax; + int specialValue; + + MS_Message(MSG_DEBUG, "---- LeadingFunction ----\n"); + argCountMin = tk_SpecialArgCount & 0xffff; + argCountMax = tk_SpecialArgCount >> 16; + specialValue = -tk_SpecialValue; + TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN); + i = 0; + if(argCountMax > 0) + { + if(TK_NextToken() == TK_CONST) + { + // Just skip const declarators + TK_NextTokenMustBe(TK_COLON, ERR_MISSING_COLON); + } + else + { + TK_Undo(); + } + do + { + if(i == argCountMax) + { + ERR_Error(ERR_BAD_ARG_COUNT, YES); + i = argCountMax+1; + } + TK_NextToken(); + EvalExpression(); + if (i == 0 && executewait) + { + PC_AppendCmd(PCD_DUP); + } + if(i < argCountMax) + { + i++; + } + } while(tk_Token == TK_COMMA); + if(i < argCountMin) + { + ERR_Error(ERR_BAD_ARG_COUNT, YES); + TK_SkipPast(TK_SEMICOLON); + return; + } + argCount = i; + } + else + { + argCount = 0; + TK_NextToken (); + } + TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN); + TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON); + PC_AppendCmd(PCD_CALLFUNC); + if(pc_NoShrink) + { + PC_AppendInt(argCount); + PC_AppendInt(specialValue); + } + else + { + PC_AppendByte((U_BYTE)argCount); + PC_AppendWord((U_WORD)specialValue); + } + PC_AppendCmd(PCD_DROP); + if(executewait) + { + PC_AppendCmd(PCD_SCRIPTWAITNAMED); + } + TK_NextToken(); +} + +//========================================================================== +// +// LeadingIdentifier +// +//========================================================================== + +static void LeadingIdentifier(void) +{ + symbolNode_t *sym; + + sym = SpeculateSymbol(tk_String, NO); + switch(sym->type) + { + case SY_MAPARRAY: + case SY_SCRIPTVAR: + case SY_SCRIPTALIAS: + case SY_MAPVAR: + case SY_WORLDVAR: + case SY_GLOBALVAR: + case SY_SCRIPTARRAY: + case SY_WORLDARRAY: + case SY_GLOBALARRAY: + LeadingVarAssign(sym); + break; + case SY_INTERNFUNC: + LeadingInternFunc(sym); + break; + case SY_SCRIPTFUNC: + LeadingScriptFunc(sym); + break; + default: + break; + } +} + +//========================================================================== +// +// LeadingInternFunc +// +//========================================================================== + +static void LeadingInternFunc(symbolNode_t *sym) +{ + if(InsideFunction && sym->info.internFunc.latent) + { + ERR_Error(ERR_LATENT_IN_FUNC, YES); + } + ProcessInternFunc(sym); + if(sym->info.internFunc.hasReturnValue == YES) + { + PC_AppendCmd(PCD_DROP); + } + TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON); + TK_NextToken(); +} + +//========================================================================== +// +// ProcessInternFunc +// +//========================================================================== + +static void ProcessInternFunc(symbolNode_t *sym) +{ + int i; + int argCount; + int optMask; + int outMask; + boolean direct; + boolean specialDirect; + int argSave[8]; + + MS_Message(MSG_DEBUG, "---- ProcessInternFunc ----\n"); + argCount = sym->info.internFunc.argCount; + optMask = sym->info.internFunc.optMask; + outMask = sym->info.internFunc.outMask; + TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN); + if(TK_NextToken() == TK_CONST) + { + TK_NextTokenMustBe(TK_COLON, ERR_MISSING_COLON); + if(sym->info.internFunc.directCommand == PCD_NOP) + { + ERR_Error(ERR_NO_DIRECT_VER, YES, NULL); + direct = NO; + specialDirect = NO; + } + else + { + direct = YES; + if (pc_NoShrink || argCount > 2 || + (sym->info.internFunc.directCommand != PCD_DELAYDIRECT && + sym->info.internFunc.directCommand != PCD_RANDOMDIRECT)) + { + specialDirect = NO; + PC_AppendCmd(sym->info.internFunc.directCommand); + } + else + { + specialDirect = YES; + } + } + TK_NextToken(); + } + else + { + direct = NO; + specialDirect = NO; // keep GCC quiet + } + i = 0; + if(argCount > 0) + { + if(tk_Token == TK_RPAREN) + { + ERR_Error(ERR_MISSING_PARAM, YES); + } + else + { + TK_Undo(); // Adjust for first expression + do + { + if(i == argCount) + { + ERR_Error(ERR_BAD_ARG_COUNT, YES); + TK_SkipTo(TK_SEMICOLON); + TK_Undo(); + return; + } + TK_NextToken(); + if(direct == YES) + { + if (tk_Token != TK_COMMA) + { + if (specialDirect) + { + argSave[i] = EvalConstExpression(); + } + else + { + PC_AppendInt(EvalConstExpression()); + } + } + else + { + if (optMask & 1) + { + if (specialDirect) + { + argSave[i] = 0; + } + else + { + PC_AppendInt(0); + } + } + else + { + ERR_Error(ERR_MISSING_PARAM, YES); + } + } + } + else + { + if (tk_Token != TK_COMMA) + { + if (!(outMask & 1)) + { + EvalExpression(); + } + else if (tk_Token != TK_IDENTIFIER) + { + ERR_Error (ERR_PARM_MUST_BE_VAR, YES); + do + { + TK_NextToken(); + } while (tk_Token != TK_COMMA && tk_Token != TK_RPAREN); + } + else + { + symbolNode_t *sym = DemandSymbol (tk_String); + PC_AppendCmd (PCD_PUSHNUMBER); + switch (sym->type) + { + case SY_SCRIPTVAR: + PC_AppendInt(sym->info.var.index | OUTVAR_SCRIPT_SPEC); + break; + case SY_MAPVAR: + PC_AppendInt(sym->info.var.index | OUTVAR_MAP_SPEC); + break; + case SY_WORLDVAR: + PC_AppendInt(sym->info.var.index | OUTVAR_WORLD_SPEC); + break; + case SY_GLOBALVAR: + PC_AppendInt(sym->info.var.index | OUTVAR_GLOBAL_SPEC); + break; + default: + ERR_Error (ERR_PARM_MUST_BE_VAR, YES); + do + { + TK_NextToken(); + } while (tk_Token != TK_COMMA && tk_Token != TK_RPAREN); + break; + } + TK_NextToken (); + } + } + else + { + if (optMask & 1) + { + PC_AppendPushVal(0); + } + else + { + ERR_Error(ERR_MISSING_PARAM, YES); + } + } + } + i++; + optMask >>= 1; + outMask >>= 1; + } while(tk_Token == TK_COMMA); + } + } + while (i < argCount && (optMask & 1)) + { + if (direct == YES) + { + if (specialDirect) + { + argSave[i] = 0; + } + else + { + PC_AppendInt(0); + } + } + else + { + PC_AppendPushVal(0); + } + i++; + optMask >>= 1; + } + if(i != argCount && i > 0) + { + ERR_Error(ERR_BAD_ARG_COUNT, YES); + } + TK_TokenMustBe(TK_RPAREN, argCount > 0 ? ERR_MISSING_RPAREN : ERR_BAD_ARG_COUNT); + if(direct == NO) + { + PC_AppendCmd(sym->info.internFunc.stackCommand); + } + else if (specialDirect) + { + boolean useintform = NO; + pcd_t shortpcd; + + switch (sym->info.internFunc.directCommand) + { + case PCD_DELAYDIRECT: + shortpcd = PCD_DELAYDIRECTB; + break; + case PCD_RANDOMDIRECT: + shortpcd = PCD_RANDOMDIRECTB; + break; + default: + useintform = YES; + shortpcd = PCD_NOP; + break; + } + + if (!useintform) + { + for (i = 0; i < argCount; i++) + { + if ((U_INT)argSave[i] > 255) + { + useintform = YES; + break; + } + } + } + + if (useintform) + { + PC_AppendCmd(sym->info.internFunc.directCommand); + for (i = 0; i < argCount; i++) + { + PC_AppendInt (argSave[i]); + } + } + else + { + PC_AppendCmd (shortpcd); + for (i = 0; i < argCount; i++) + { + PC_AppendByte ((U_BYTE)argSave[i]); + } + } + } + TK_NextToken(); +} + +//========================================================================== +// +// LeadingScriptFunc +// +//========================================================================== + +static void LeadingScriptFunc(symbolNode_t *sym) +{ + ProcessScriptFunc(sym, YES); + TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON); + TK_NextToken(); +} + + +//========================================================================== +// +// ProcessScriptFunc +// +//========================================================================== + +static void ProcessScriptFunc(symbolNode_t *sym, boolean discardReturn) +{ + int i; + int argCount; + + MS_Message(MSG_DEBUG, "---- ProcessScriptFunc ----\n"); + if(sym->info.scriptFunc.predefined == YES && discardReturn == NO) + { + sym->info.scriptFunc.hasReturnValue = YES; + } + argCount = sym->info.scriptFunc.argCount; + TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN); + i = 0; + if(argCount == 0) + { + TK_NextTokenMustBe(TK_RPAREN, ERR_BAD_ARG_COUNT); + } + else if(argCount > 0) + { + TK_NextToken(); + if(tk_Token == TK_RPAREN) + { + ERR_Error(ERR_BAD_ARG_COUNT, YES); + TK_SkipTo(TK_SEMICOLON); + return; + } + TK_Undo(); + do + { + if(i == argCount) + { + ERR_Error(ERR_BAD_ARG_COUNT, YES); + TK_SkipTo(TK_SEMICOLON); + return; + } + TK_NextToken(); + if (tk_Token != TK_COMMA) + { + EvalExpression(); + } + else + { + ERR_Error(ERR_MISSING_PARAM, YES); + TK_SkipTo(TK_SEMICOLON); + return; + } + i++; + } while(tk_Token == TK_COMMA); + } + if(argCount < 0) + { // Function has not been defined yet, so assume arg count is correct + TK_NextToken(); + while (tk_Token != TK_RPAREN) + { + EvalExpression(); + i++; + if (tk_Token == TK_COMMA) + { + TK_NextToken(); + } + else if (tk_Token != TK_RPAREN) + { + ERR_Error(ERR_MISSING_PARAM, YES); + TK_SkipTo(TK_SEMICOLON); + return; + } + } + } + else if(i != argCount) + { + ERR_Error(ERR_BAD_ARG_COUNT, YES); + TK_SkipTo(TK_SEMICOLON); + return; + } + TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN); + PC_AppendCmd(discardReturn ? PCD_CALLDISCARD : PCD_CALL); + if(sym->info.scriptFunc.predefined && ImportMode != IMPORT_Importing) + { + AddScriptFuncRef(sym, pc_Address, i); + } + if (pc_NoShrink) + { + PC_AppendInt(sym->info.scriptFunc.funcNumber); + } + else + { + PC_AppendByte((U_BYTE)sym->info.scriptFunc.funcNumber); + } + TK_NextToken(); +} + +//========================================================================== +// +// BuildPrintString +// +//========================================================================== + +static void BuildPrintString(void) +{ + pcd_t printCmd; + + do + { + switch(TK_NextCharacter()) + { + case 'a': // character array support [JB] + ActionOnCharRange(NO); + continue; + case 's': // string + printCmd = PCD_PRINTSTRING; + break; + case 'l': // [RH] localized string + printCmd = PCD_PRINTLOCALIZED; + break; + case 'i': // integer + case 'd': // decimal + printCmd = PCD_PRINTNUMBER; + break; + case 'c': // character + printCmd = PCD_PRINTCHARACTER; + break; + case 'n': // [BC] name + printCmd = PCD_PRINTNAME; + break; + case 'f': // [RH] fixed point + printCmd = PCD_PRINTFIXED; + break; + case 'k': // [GRB] key binding + printCmd = PCD_PRINTBIND; + break; + case 'b': // [RH] binary integer + printCmd = PCD_PRINTBINARY; + break; + case 'x': // [RH] hexadecimal integer + printCmd = PCD_PRINTHEX; + break; + default: + printCmd = PCD_PRINTSTRING; + ERR_Error(ERR_UNKNOWN_PRTYPE, YES); + break; + } + TK_NextTokenMustBe(TK_COLON, ERR_MISSING_COLON); + TK_NextToken(); + EvalExpression(); + PC_AppendCmd(printCmd); + } while(tk_Token == TK_COMMA); +} + +//========================================================================== +// +// ActionOnCharRange // FDARI (mutation of PrintCharArray // JB) +// +//========================================================================== + +static void ActionOnCharRange(boolean write) +{ + boolean rangeConstraints; + symbolNode_t *sym; + TK_NextTokenMustBe(TK_COLON, ERR_MISSING_COLON); + TK_NextToken(); + + if (tk_Token == TK_LPAREN) + { + rangeConstraints = YES; + TK_NextToken(); + } + else + { + rangeConstraints = NO; + } + + sym = SpeculateSymbol(tk_String, NO); + if((sym->type != SY_MAPARRAY) && (sym->type != SY_WORLDARRAY) + && (sym->type != SY_GLOBALARRAY) && (sym->type != SY_SCRIPTARRAY)) + { + ERR_Error(ERR_NOT_AN_ARRAY, YES, sym->name); + } + TK_NextToken(); + if(sym->info.array.ndim > 1) + { + ParseArrayIndices(sym, sym->info.array.ndim-1); + } + else + { + PC_AppendPushVal(0); + } + + PC_AppendPushVal(sym->info.array.index); + + + if (rangeConstraints) + { + switch (tk_Token) + { + case TK_RPAREN: + rangeConstraints = NO; + TK_NextToken(); + break; + case TK_COMMA: + TK_NextToken(); + EvalExpression(); + + switch (tk_Token) + { + case TK_RPAREN: + TK_NextToken(); + PC_AppendPushVal(0x7FFFFFFF); + break; + case TK_COMMA: + TK_NextToken(); + EvalExpression(); // limit on capacity + TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN); + TK_NextToken(); + break; + default: + ERR_Error(ERR_MISSING_RPAREN, YES); + break; + } + + break; + default: + ERR_Error(ERR_MISSING_RPAREN, YES); + break; + } + } + + if (write) + { + if (!rangeConstraints) + { + PC_AppendPushVal(0); + PC_AppendPushVal(0x7FFFFFFF); + } + + TK_TokenMustBe(TK_COMMA, ERR_MISSING_COMMA); + TK_NextToken(); + EvalExpression(); + + if (tk_Token == TK_COMMA) + { + TK_NextToken(); + EvalExpression(); + } + else + { + PC_AppendPushVal(0); + } + } + + if(sym->type == SY_SCRIPTARRAY) + { + if (write) PC_AppendCmd(PCD_STRCPYTOSCRIPTCHRANGE); + else PC_AppendCmd( rangeConstraints ? PCD_PRINTSCRIPTCHRANGE : PCD_PRINTSCRIPTCHARARRAY ); + } + else if(sym->type == SY_MAPARRAY) + { + if (write) PC_AppendCmd(PCD_STRCPYTOMAPCHRANGE); + else PC_AppendCmd( rangeConstraints ? PCD_PRINTMAPCHRANGE : PCD_PRINTMAPCHARARRAY ); + } + else if(sym->type == SY_WORLDARRAY) + { + if (write) PC_AppendCmd(PCD_STRCPYTOWORLDCHRANGE); + else PC_AppendCmd( rangeConstraints ? PCD_PRINTWORLDCHRANGE : PCD_PRINTWORLDCHARARRAY ); + } + else // if(sym->type == SY_GLOBALARRAY) + { + if (write) PC_AppendCmd(PCD_STRCPYTOGLOBALCHRANGE); + else PC_AppendCmd( rangeConstraints ? PCD_PRINTGLOBALCHRANGE : PCD_PRINTGLOBALCHARARRAY ); + } +} + +//========================================================================== +// +// LeadingStrcpy +// +//========================================================================== + +static void LeadingStrcpy(void) +{ + MS_Message(MSG_DEBUG, "---- LeadingStrcpy ----\n"); + TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN); + + switch(TK_NextCharacter()) // structure borrowed from printbuilder + { + case 'a': + ActionOnCharRange(YES); + break; + + default: + ERR_Error(ERR_UNKNOWN_PRTYPE, YES); + break; + } + + TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN); +} + +//========================================================================== +// +// LeadingPrint +// +//========================================================================== + +static void LeadingPrint(void) +{ + tokenType_t stmtToken; + + MS_Message(MSG_DEBUG, "---- LeadingPrint ----\n"); + stmtToken = tk_Token; // Will be TK_PRINT or TK_PRINTBOLD, TK_LOG or TK_STRPARAM_EVAL [FDARI] + PC_AppendCmd(PCD_BEGINPRINT); + TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN); + BuildPrintString(); + TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN); + + switch (stmtToken) + { + case TK_PRINT: + PC_AppendCmd(PCD_ENDPRINT); + break; + + case TK_PRINTBOLD: + PC_AppendCmd(PCD_ENDPRINTBOLD); + break; + + case TK_STRPARAM_EVAL: + PC_AppendCmd(PCD_SAVESTRING); + return; // THE CALLER MUST DO THE POST-PROCESSING + + case TK_LOG: + default: + PC_AppendCmd(PCD_ENDLOG); + break; + } + + TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON); + TK_NextToken(); +} + +//========================================================================== +// +// LeadingHudMessage +// +// hudmessage(str text; int type, int id, int color, fixed x, fixed y, fixed holdtime, ...) +// +//========================================================================== + +static void LeadingHudMessage(void) +{ + tokenType_t stmtToken; + int i; + + MS_Message(MSG_DEBUG, "---- LeadingHudMessage ----\n"); + stmtToken = tk_Token; // Will be TK_HUDMESSAGE or TK_HUDMESSAGEBOLD + PC_AppendCmd(PCD_BEGINPRINT); + TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN); + BuildPrintString(); + TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_PARAM); + PC_AppendCmd(PCD_MOREHUDMESSAGE); + for (i = 6; i > 0; i--) + { + TK_NextToken(); + EvalExpression(); + if (i > 1) + TK_TokenMustBe(TK_COMMA, ERR_MISSING_PARAM); + } + if (tk_Token == TK_COMMA) + { // HUD message has optional parameters + PC_AppendCmd(PCD_OPTHUDMESSAGE); + do + { + TK_NextToken(); + EvalExpression(); + } while (tk_Token == TK_COMMA); + } + TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN); + PC_AppendCmd(stmtToken == TK_HUDMESSAGE ? + PCD_ENDHUDMESSAGE : PCD_ENDHUDMESSAGEBOLD); + TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON); + TK_NextToken(); +} + +//========================================================================== +// +// LeadingMorphActor +// +// MorphActor(int tid, [str playerclass, [str monsterclass, [int duration, [int style, [str morphflash, [str unmorphflash]]]]]]) +// +//========================================================================== + +static void LeadingMorphActor(void) +{ + int i; + byte strMask; + + MS_Message(MSG_DEBUG, "---- LeadingMorphActor ----\n"); + strMask = 0b01100110; + + TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN); + if(TK_NextToken() == TK_CONST) + { + TK_NextTokenMustBe(TK_COLON, ERR_MISSING_COLON); + ERR_Error(ERR_NO_DIRECT_VER, YES, NULL); + TK_NextToken(); + } + i = 0; + if(tk_Token == TK_RPAREN) + { + ERR_Error(ERR_MISSING_PARAM, YES); + } + else + { + TK_Undo(); // Adjust for first expression + do + { + if(i == 7) + { + ERR_Error(ERR_BAD_ARG_COUNT, YES); + TK_SkipTo(TK_SEMICOLON); + TK_Undo(); + return; + } + TK_NextToken(); + + if(tk_Token != TK_COMMA) + { + EvalExpression(); + } + else + { + if(i > 0) + { + if(strMask & 1) + { + PC_AppendPushVal(STR_Find("")); + } + else + { + PC_AppendPushVal(0); + } + } + else + { + ERR_Error(ERR_MISSING_PARAM, YES); + } + } + i++; + strMask >>= 1; + } while(tk_Token == TK_COMMA); + } + while(i < 7) + { + if(strMask & 1) + { + PC_AppendPushVal(STR_Find("")); + } + else + { + PC_AppendPushVal(0); + } + i++; + strMask >>= 1; + } + if(i != 7) + { + ERR_Error(ERR_BAD_ARG_COUNT, YES); + } + TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN); + PC_AppendCmd(PCD_MORPHACTOR); +} + +//========================================================================== +// +// LeadingCreateTranslation +// +// Simple grammar: +// +// tranlationstmt: CreateTranslation ( exp opt_args ) ; +// opt_args: /* empty: just reset the translation */ | , arglist +// arglist: arg | arglist arg +// arg: range = replacement +// range: exp : exp +// replacement: palrep | colorrep | desatrep | colouriserep | tintrep +// palrep: exp : exp +// colorrep: [exp,exp,exp]:[exp,exp,exp] +// desatrep: %colorrep +// colouriserep: #[exp,exp,exp] +// tintrep: @exp[exp,exp,exp] +//========================================================================== + +static void LeadingCreateTranslation(void) +{ + MS_Message(MSG_DEBUG, "---- LeadingCreateTranslation ----\n"); + TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN); + TK_NextToken(); + EvalExpression(); + PC_AppendCmd(PCD_STARTTRANSLATION); + while (tk_Token == TK_COMMA) + { + pcd_t translationcode; + + TK_NextToken(); + EvalExpression(); // Get first palette entry in range + TK_TokenMustBe(TK_COLON, ERR_MISSING_COLON); + TK_NextToken(); + EvalExpression(); // Get second palette entry in range + TK_TokenMustBe(TK_ASSIGN, ERR_MISSING_ASSIGN); + + TK_NextToken(); + if(tk_Token == TK_PERCENT) + { + translationcode = PCD_TRANSLATIONRANGE3; + TK_NextTokenMustBe(TK_LBRACKET, ERR_MISSING_LBRACKET); + } + else if (tk_Token == TK_NUMBERSIGN) + { + translationcode = PCD_TRANSLATIONRANGE4; + TK_NextTokenMustBe(TK_LBRACKET, ERR_MISSING_LBRACKET); + } + else if (tk_Token == TK_ATSIGN) + { + translationcode = PCD_TRANSLATIONRANGE5; + TK_NextToken(); + EvalExpression(); + TK_TokenMustBe(TK_LBRACKET, ERR_MISSING_LBRACKET); + } + else + { + translationcode = PCD_TRANSLATIONRANGE2; + } + if(tk_Token == TK_LBRACKET) + { // Replacement is color range + int i, j; + + TK_NextToken(); + + for(j = 2; j != 0; --j) + { + for(i = 3; i != 0; --i) + { + EvalExpression(); + if(i != 1) + { + TK_TokenMustBe(TK_COMMA, ERR_MISSING_COMMA); + } + else + { + TK_TokenMustBe(TK_RBRACKET, ERR_MISSING_RBRACKET); + } + TK_NextToken(); + } + if (translationcode == PCD_TRANSLATIONRANGE4 || translationcode == PCD_TRANSLATIONRANGE5) + break; + if(j == 2) + { + TK_TokenMustBe(TK_COLON, ERR_MISSING_COLON); + TK_NextTokenMustBe(TK_LBRACKET, ERR_MISSING_LBRACKET); + TK_NextToken(); + } + } + } + else + { // Replacement is palette range + EvalExpression(); + TK_TokenMustBe(TK_COLON, ERR_MISSING_COLON); + TK_NextToken(); + EvalExpression(); + translationcode = PCD_TRANSLATIONRANGE1; + } + PC_AppendCmd(translationcode); + } + PC_AppendCmd(PCD_ENDTRANSLATION); + TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN); + TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON); + TK_NextToken(); +} + +//========================================================================== +// +// LeadingIf +// +//========================================================================== + +static void LeadingIf(void) +{ + int jumpAddrPtr1; + int jumpAddrPtr2; + + MS_Message(MSG_DEBUG, "---- LeadingIf ----\n"); + TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN); + TK_NextToken(); + EvalExpression(); + TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN); + PC_AppendCmd(PCD_IFNOTGOTO); + jumpAddrPtr1 = pc_Address; + PC_SkipInt(); + TK_NextToken(); + if(ProcessStatement(STMT_IF) == NO) + { + ERR_Error(ERR_INVALID_STATEMENT, YES); + } + if(tk_Token == TK_ELSE) + { + PC_AppendCmd(PCD_GOTO); + jumpAddrPtr2 = pc_Address; + PC_SkipInt(); + PC_WriteInt(pc_Address, jumpAddrPtr1); + TK_NextToken(); + if(ProcessStatement(STMT_ELSE) == NO) + { + ERR_Error(ERR_INVALID_STATEMENT, YES); + } + PC_WriteInt(pc_Address, jumpAddrPtr2); + } + else + { + PC_WriteInt(pc_Address, jumpAddrPtr1); + } +} + +//========================================================================== +// +// LeadingFor +// +//========================================================================== + +static void LeadingFor(void) +{ + int exprAddr; + int incAddr; + int ifgotoAddr; + int gotoAddr; + + MS_Message(MSG_DEBUG, "---- LeadingFor ----\n"); + TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN); + TK_NextToken(); + if(ProcessStatement(STMT_IF) == NO) + { + ERR_Error(ERR_INVALID_STATEMENT, YES); + } + exprAddr = pc_Address; + EvalExpression(); + TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON); + TK_NextToken(); + PC_AppendCmd(PCD_IFGOTO); + ifgotoAddr = pc_Address; + PC_SkipInt(); + PC_AppendCmd(PCD_GOTO); + gotoAddr = pc_Address; + PC_SkipInt(); + incAddr = pc_Address; + forSemicolonHack = TRUE; + if(ProcessStatement(STMT_IF) == NO) + { + ERR_Error(ERR_INVALID_STATEMENT, YES); + } + forSemicolonHack = FALSE; + PC_AppendCmd(PCD_GOTO); + PC_AppendInt(exprAddr); + PC_WriteInt(pc_Address,ifgotoAddr); + if(ProcessStatement(STMT_FOR) == NO) + { + ERR_Error(ERR_INVALID_STATEMENT, YES); + } + PC_AppendCmd(PCD_GOTO); + PC_AppendInt(incAddr); + WriteContinues(incAddr); + WriteBreaks(); + PC_WriteInt(pc_Address,gotoAddr); +} + +//========================================================================== +// +// LeadingWhileUntil +// +//========================================================================== + +static void LeadingWhileUntil(void) +{ + tokenType_t stmtToken; + int topAddr; + int outAddrPtr; + + MS_Message(MSG_DEBUG, "---- LeadingWhileUntil ----\n"); + stmtToken = tk_Token; + topAddr = pc_Address; + TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN); + TK_NextToken(); + EvalExpression(); + TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN); + PC_AppendCmd(stmtToken == TK_WHILE ? PCD_IFNOTGOTO : PCD_IFGOTO); + outAddrPtr = pc_Address; + PC_SkipInt(); + TK_NextToken(); + if(ProcessStatement(STMT_WHILEUNTIL) == NO) + { + ERR_Error(ERR_INVALID_STATEMENT, YES); + } + PC_AppendCmd(PCD_GOTO); + PC_AppendInt(topAddr); + + PC_WriteInt(pc_Address, outAddrPtr); + + WriteContinues(topAddr); + WriteBreaks(); +} + +//========================================================================== +// +// LeadingDo +// +//========================================================================== + +static void LeadingDo(void) +{ + int topAddr; + int exprAddr; + tokenType_t stmtToken; + + MS_Message(MSG_DEBUG, "---- LeadingDo ----\n"); + topAddr = pc_Address; + TK_NextToken(); + if(ProcessStatement(STMT_DO) == NO) + { + ERR_Error(ERR_INVALID_STATEMENT, YES, NULL); + } + if(tk_Token != TK_WHILE && tk_Token != TK_UNTIL) + { + ERR_Error(ERR_BAD_DO_STATEMENT, YES, NULL); + TK_SkipPast(TK_SEMICOLON); + return; + } + stmtToken = tk_Token; + TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN); + exprAddr = pc_Address; + TK_NextToken(); + EvalExpression(); + TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN); + TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON); + PC_AppendCmd(stmtToken == TK_WHILE ? PCD_IFGOTO : PCD_IFNOTGOTO); + PC_AppendInt(topAddr); + WriteContinues(exprAddr); + WriteBreaks(); + TK_NextToken(); +} + +//========================================================================== +// +// LeadingSwitch +// +//========================================================================== + +static void LeadingSwitch(void) +{ + int switcherAddrPtr; + int outAddrPtr; + caseInfo_t *cInfo; + int defaultAddress; + + MS_Message(MSG_DEBUG, "---- LeadingSwitch ----\n"); + + TK_NextTokenMustBe(TK_LPAREN, ERR_MISSING_LPAREN); + TK_NextToken(); + EvalExpression(); + TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN); + + PC_AppendCmd(PCD_GOTO); + switcherAddrPtr = pc_Address; + PC_SkipInt(); + + TK_NextToken(); + if(ProcessStatement(STMT_SWITCH) == NO) + { + ERR_Error(ERR_INVALID_STATEMENT, YES, NULL); + } + + PC_AppendCmd(PCD_GOTO); + outAddrPtr = pc_Address; + PC_SkipInt(); + + PC_WriteInt(pc_Address, switcherAddrPtr); + defaultAddress = 0; + + if(pc_HexenCase) + { + while((cInfo = GetCaseInfo()) != NULL) + { + if(cInfo->isDefault == YES) + { + defaultAddress = cInfo->address; + continue; + } + PC_AppendCmd(PCD_CASEGOTO); + PC_AppendInt(cInfo->value); + PC_AppendInt(cInfo->address); + } + } + else if(CaseIndex != 0) + { + caseInfo_t *maxCase = &CaseInfo[CaseIndex]; + caseInfo_t *minCase = maxCase; + + // [RH] Sort cases so that the VM can handle them with + // a quick binary search. + while((cInfo = GetCaseInfo()) != NULL) + { + minCase = cInfo; + } + qsort(minCase, maxCase - minCase, sizeof(caseInfo_t), CaseInfoCmp); + if(minCase->isDefault == YES) + { + defaultAddress = minCase->address; + minCase++; + } + if (minCase < maxCase) + { + PC_AppendCmd(PCD_CASEGOTOSORTED); + if(pc_Address%4 != 0) + { // Align to a 4-byte boundary + U_INT pad = 0; + PC_Append((void *)&pad, 4-(pc_Address%4)); + } + PC_AppendInt(maxCase - minCase); + for(; minCase < maxCase; ++minCase) + { + PC_AppendInt(minCase->value); + PC_AppendInt(minCase->address); + } + } + } + PC_AppendCmd(PCD_DROP); + + if(defaultAddress != 0) + { + PC_AppendCmd(PCD_GOTO); + PC_AppendInt(defaultAddress); + } + + PC_WriteInt(pc_Address, outAddrPtr); + + WriteBreaks(); +} + +//========================================================================== +// +// LeadingCase +// +//========================================================================== + +static void LeadingCase(void) +{ + MS_Message(MSG_DEBUG, "---- LeadingCase ----\n"); + TK_NextToken(); + PushCase(EvalConstExpression(), NO); + TK_TokenMustBe(TK_COLON, ERR_MISSING_COLON); + TK_NextToken(); +} + +//========================================================================== +// +// LeadingDefault +// +//========================================================================== + +static void LeadingDefault(void) +{ + MS_Message(MSG_DEBUG, "---- LeadingDefault ----\n"); + TK_NextTokenMustBe(TK_COLON, ERR_MISSING_COLON); + PushCase(0, YES); + TK_NextToken(); +} + +//========================================================================== +// +// PushCase +// +//========================================================================== + +static void PushCase(int value, boolean isDefault) +{ + if(CaseIndex == MAX_CASE) + { + ERR_Exit(ERR_CASE_OVERFLOW, YES); + } + CaseInfo[CaseIndex].level = StatementLevel; + CaseInfo[CaseIndex].value = value; + CaseInfo[CaseIndex].isDefault = isDefault; + CaseInfo[CaseIndex].address = pc_Address; + CaseIndex++; +} + +//========================================================================== +// +// GetCaseInfo +// +//========================================================================== + +static caseInfo_t *GetCaseInfo(void) +{ + if(CaseIndex == 0) + { + return NULL; + } + if(CaseInfo[CaseIndex-1].level > StatementLevel) + { + return &CaseInfo[--CaseIndex]; + } + return NULL; +} + +//========================================================================== +// +// CaseInfoCmp +// +//========================================================================== + +static int CaseInfoCmp (const void *a, const void *b) +{ + const caseInfo_t *ca = (const caseInfo_t *)a; + const caseInfo_t *cb = (const caseInfo_t *)b; + + // The default case always gets moved to the front. + if(ca->isDefault) + { + return -1; + } + if(cb->isDefault) + { + return 1; + } + return ca->value - cb->value; +} + +//========================================================================== +// +// DefaultInCurrent +// +//========================================================================== + +static boolean DefaultInCurrent(void) +{ + int i; + + for(i = 0; i < CaseIndex; i++) + { + if(CaseInfo[i].isDefault == YES + && CaseInfo[i].level == StatementLevel) + { + return YES; + } + } + return NO; +} + +//========================================================================== +// +// LeadingBreak +// +//========================================================================== + +static void LeadingBreak(void) +{ + MS_Message(MSG_DEBUG, "---- LeadingBreak ----\n"); + TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON); + PC_AppendCmd(PCD_GOTO); + PushBreak(); + PC_SkipInt(); + TK_NextToken(); +} + +//========================================================================== +// +// PushBreak +// +//========================================================================== + +static void PushBreak(void) +{ + if(BreakIndex == MAX_CASE) + { + ERR_Exit(ERR_BREAK_OVERFLOW, YES); + } + BreakInfo[BreakIndex].level = StatementLevel; + BreakInfo[BreakIndex].addressPtr = pc_Address; + BreakIndex++; +} + +//========================================================================== +// +// WriteBreaks +// +//========================================================================== + +static void WriteBreaks(void) +{ + while(BreakIndex && BreakInfo[BreakIndex-1].level > StatementLevel) + { + PC_WriteInt(pc_Address, BreakInfo[--BreakIndex].addressPtr); + } +} + +//========================================================================== +// +// BreakAncestor +// +// Returns YES if the current statement history contains a break root +// statement. +// +//========================================================================== + +static boolean BreakAncestor(void) +{ + int i; + + for(i = 0; i < StatementIndex; i++) + { + if(IsBreakRoot[StatementHistory[i]]) + { + return YES; + } + } + return NO; +} + +//========================================================================== +// +// LeadingContinue +// +//========================================================================== + +static void LeadingContinue(void) +{ + MS_Message(MSG_DEBUG, "---- LeadingContinue ----\n"); + TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON); + PC_AppendCmd(PCD_GOTO); + PushContinue(); + PC_SkipInt(); + TK_NextToken(); +} + +//========================================================================== +// +// PushContinue +// +//========================================================================== + +static void PushContinue(void) +{ + if(ContinueIndex == MAX_CONTINUE) + { + ERR_Exit(ERR_CONTINUE_OVERFLOW, YES); + } + ContinueInfo[ContinueIndex].level = StatementLevel; + ContinueInfo[ContinueIndex].addressPtr = pc_Address; + ContinueIndex++; +} + +//========================================================================== +// +// WriteContinues +// +//========================================================================== + +static void WriteContinues(int address) +{ + if(ContinueIndex == 0) + { + return; + } + while(ContinueInfo[ContinueIndex-1].level > StatementLevel) + { + PC_WriteInt(address, ContinueInfo[--ContinueIndex].addressPtr); + } +} + +//========================================================================== +// +// ContinueAncestor +// +//========================================================================== + +static boolean ContinueAncestor(void) +{ + int i; + + for(i = 0; i < StatementIndex; i++) + { + if(IsContinueRoot[StatementHistory[i]]) + { + return YES; + } + } + return NO; +} + +//========================================================================== +// +// LeadingIncDec +// +//========================================================================== + +static void LeadingIncDec(int token) +{ + symbolNode_t *sym; + + MS_Message(MSG_DEBUG, "---- LeadingIncDec ----\n"); + TK_NextTokenMustBe(TK_IDENTIFIER, ERR_INCDEC_OP_ON_NON_VAR); + sym = DemandSymbol(tk_String); + if(sym->type != SY_SCRIPTVAR && sym->type != SY_MAPVAR + && sym->type != SY_WORLDVAR && sym->type != SY_GLOBALVAR + && sym->type != SY_MAPARRAY && sym->type != SY_GLOBALARRAY + && sym->type != SY_WORLDARRAY && sym->type != SY_SCRIPTALIAS + && sym->type != SY_SCRIPTARRAY) + { + ERR_Error(ERR_INCDEC_OP_ON_NON_VAR, YES); + TK_SkipPast(TK_SEMICOLON); + return; + } + TK_NextToken(); + if(sym->type == SY_MAPARRAY || sym->type == SY_WORLDARRAY + || sym->type == SY_GLOBALARRAY || sym->type == SY_SCRIPTARRAY) + { + ParseArrayIndices(sym, sym->info.array.ndim); + } + else if(tk_Token == TK_LBRACKET) + { + ERR_Error(ERR_NOT_AN_ARRAY, YES, sym->name); + while(tk_Token == TK_LBRACKET) + { + TK_SkipPast(TK_RBRACKET); + } + } + PC_AppendCmd(GetIncDecPCD(token, sym->type)); + PC_AppendShrink(sym->info.var.index); + if(forSemicolonHack) + { + TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN); + } + else + { + TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON); + } + TK_NextToken(); +} + +//========================================================================== +// +// LeadingVarAssign +// +//========================================================================== + +static void LeadingVarAssign(symbolNode_t *sym) +{ + boolean done; + tokenType_t assignToken; + + MS_Message(MSG_DEBUG, "---- LeadingVarAssign ----\n"); + done = NO; + do + { + TK_NextToken(); // Fetch assignment operator + if(sym->type == SY_MAPARRAY || sym->type == SY_WORLDARRAY + || sym->type == SY_GLOBALARRAY || sym->type == SY_SCRIPTARRAY) + { + ParseArrayIndices(sym, sym->info.array.ndim); + } + else if(tk_Token == TK_LBRACKET) + { + ERR_Error(ERR_NOT_AN_ARRAY, YES, sym->name); + while(tk_Token == TK_LBRACKET) + { + TK_SkipPast(TK_RBRACKET); + } + } + if(tk_Token == TK_INC || tk_Token == TK_DEC) + { // Postfix increment or decrement + PC_AppendCmd(GetIncDecPCD(tk_Token, sym->type)); + if (pc_NoShrink) + { + PC_AppendInt(sym->info.var.index); + } + else + { + PC_AppendByte(sym->info.var.index); + } + TK_NextToken(); + } + else + { // Normal operator + if(TK_Member(AssignOps) == NO) + { + ERR_Error(ERR_MISSING_ASSIGN_OP, YES); + TK_SkipPast(TK_SEMICOLON); + return; + } + assignToken = tk_Token; + TK_NextToken(); + EvalExpression(); + PC_AppendCmd(GetAssignPCD(assignToken, sym->type)); + PC_AppendShrink(sym->info.var.index); + } + if(tk_Token == TK_COMMA) + { + TK_NextTokenMustBe(TK_IDENTIFIER, ERR_BAD_ASSIGNMENT); + sym = DemandSymbol(tk_String); + if(sym->type != SY_SCRIPTVAR && sym->type != SY_MAPVAR + && sym->type != SY_WORLDVAR && sym->type != SY_GLOBALVAR + && sym->type != SY_WORLDARRAY && sym->type != SY_GLOBALARRAY + && sym->type != SY_SCRIPTALIAS) + { + ERR_Error(ERR_BAD_ASSIGNMENT, YES); + TK_SkipPast(TK_SEMICOLON); + return; + } + } + else + { + TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON); + TK_NextToken(); + done = YES; + } + } while(done == NO); +} + +//========================================================================== +// +// GetAssignPCD +// +//========================================================================== + +static pcd_t GetAssignPCD(tokenType_t token, symbolType_t symbol) +{ + size_t i, j; + static tokenType_t tokenLookup[] = + { + TK_ASSIGN, TK_ADDASSIGN, TK_SUBASSIGN, + TK_MULASSIGN, TK_DIVASSIGN, TK_MODASSIGN, + TK_ANDASSIGN, TK_EORASSIGN, TK_ORASSIGN, + TK_LSASSIGN, TK_RSASSIGN + }; + static symbolType_t symbolLookup[] = + { + SY_SCRIPTVAR, SY_MAPVAR, SY_WORLDVAR, SY_GLOBALVAR, SY_MAPARRAY, + SY_WORLDARRAY, SY_GLOBALARRAY, SY_SCRIPTARRAY + }; + static pcd_t assignmentLookup[11][8] = + { + { PCD_ASSIGNSCRIPTVAR, PCD_ASSIGNMAPVAR, PCD_ASSIGNWORLDVAR, PCD_ASSIGNGLOBALVAR, PCD_ASSIGNMAPARRAY, PCD_ASSIGNWORLDARRAY, PCD_ASSIGNGLOBALARRAY, PCD_ASSIGNSCRIPTARRAY }, + { PCD_ADDSCRIPTVAR, PCD_ADDMAPVAR, PCD_ADDWORLDVAR, PCD_ADDGLOBALVAR, PCD_ADDMAPARRAY, PCD_ADDWORLDARRAY, PCD_ADDGLOBALARRAY, PCD_ADDSCRIPTARRAY }, + { PCD_SUBSCRIPTVAR, PCD_SUBMAPVAR, PCD_SUBWORLDVAR, PCD_SUBGLOBALVAR, PCD_SUBMAPARRAY, PCD_SUBWORLDARRAY, PCD_SUBGLOBALARRAY, PCD_SUBSCRIPTARRAY }, + { PCD_MULSCRIPTVAR, PCD_MULMAPVAR, PCD_MULWORLDVAR, PCD_MULGLOBALVAR, PCD_MULMAPARRAY, PCD_MULWORLDARRAY, PCD_MULGLOBALARRAY, PCD_MULSCRIPTARRAY }, + { PCD_DIVSCRIPTVAR, PCD_DIVMAPVAR, PCD_DIVWORLDVAR, PCD_DIVGLOBALVAR, PCD_DIVMAPARRAY, PCD_DIVWORLDARRAY, PCD_DIVGLOBALARRAY, PCD_DIVSCRIPTARRAY }, + { PCD_MODSCRIPTVAR, PCD_MODMAPVAR, PCD_MODWORLDVAR, PCD_MODGLOBALVAR, PCD_MODMAPARRAY, PCD_MODWORLDARRAY, PCD_MODGLOBALARRAY, PCD_MODSCRIPTARRAY }, + { PCD_ANDSCRIPTVAR, PCD_ANDMAPVAR, PCD_ANDWORLDVAR, PCD_ANDGLOBALVAR, PCD_ANDMAPARRAY, PCD_ANDWORLDARRAY, PCD_ANDGLOBALARRAY, PCD_ANDSCRIPTARRAY }, + { PCD_EORSCRIPTVAR, PCD_EORMAPVAR, PCD_EORWORLDVAR, PCD_EORGLOBALVAR, PCD_EORMAPARRAY, PCD_EORWORLDARRAY, PCD_EORGLOBALARRAY, PCD_EORSCRIPTARRAY }, + { PCD_ORSCRIPTVAR, PCD_ORMAPVAR, PCD_ORWORLDVAR, PCD_ORGLOBALVAR, PCD_ORMAPARRAY, PCD_ORWORLDARRAY, PCD_ORGLOBALARRAY, PCD_ORSCRIPTARRAY }, + { PCD_LSSCRIPTVAR, PCD_LSMAPVAR, PCD_LSWORLDVAR, PCD_LSGLOBALVAR, PCD_LSMAPARRAY, PCD_LSWORLDARRAY, PCD_LSGLOBALARRAY, PCD_LSSCRIPTARRAY }, + { PCD_RSSCRIPTVAR, PCD_RSMAPVAR, PCD_RSWORLDVAR, PCD_RSGLOBALVAR, PCD_RSMAPARRAY, PCD_RSWORLDARRAY, PCD_RSGLOBALARRAY, PCD_RSSCRIPTARRAY } + }; + + for(i = 0; i < ARRAY_SIZE(tokenLookup); ++i) + { + if(tokenLookup[i] == token) + { + for(j = 0; j < ARRAY_SIZE(symbolLookup); ++j) + { + if (symbolLookup[j] == symbol) + { + return assignmentLookup[i][j]; + } + } + break; + } + } + return PCD_NOP; +} + +//========================================================================== +// +// LeadingSuspend +// +//========================================================================== + +static void LeadingSuspend(void) +{ + MS_Message(MSG_DEBUG, "---- LeadingSuspend ----\n"); + if(InsideFunction) + { + ERR_Error(ERR_SUSPEND_IN_FUNCTION, YES); + } + TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON); + PC_AppendCmd(PCD_SUSPEND); + TK_NextToken(); +} + +//========================================================================== +// +// LeadingTerminate +// +//========================================================================== + +static void LeadingTerminate(void) +{ + MS_Message(MSG_DEBUG, "---- LeadingTerminate ----\n"); + if(InsideFunction) + { + ERR_Error(ERR_TERMINATE_IN_FUNCTION, YES); + } + TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON); + PC_AppendCmd(PCD_TERMINATE); + TK_NextToken(); +} + +//========================================================================== +// +// LeadingRestart +// +//========================================================================== + +static void LeadingRestart(void) +{ + MS_Message(MSG_DEBUG, "---- LeadingRestart ----\n"); + if(InsideFunction) + { + ERR_Error(ERR_RESTART_IN_FUNCTION, YES); + } + TK_NextTokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON); + PC_AppendCmd(PCD_RESTART); + TK_NextToken(); +} + +//========================================================================== +// +// LeadingReturn +// +//========================================================================== + +static void LeadingReturn(void) +{ + MS_Message(MSG_DEBUG, "---- LeadingReturn ----\n"); + if(!InsideFunction) + { + ERR_Error(ERR_RETURN_OUTSIDE_FUNCTION, YES); + while (TK_NextToken () != TK_SEMICOLON) + { + if (tk_Token == TK_EOF) + break; + } + } + else + { + TK_NextToken(); + if(tk_Token == TK_SEMICOLON) + { + if(InsideFunction->info.scriptFunc.hasReturnValue) + { + ERR_Error(ERR_MUST_RETURN_A_VALUE, YES); + } + PC_AppendCmd(PCD_RETURNVOID); + } + else + { + if(!InsideFunction->info.scriptFunc.hasReturnValue) + { + ERR_Error(ERR_MUST_NOT_RETURN_A_VALUE, YES); + } + EvalExpression(); + TK_TokenMustBe(TK_SEMICOLON, ERR_MISSING_SEMICOLON); + PC_AppendCmd(PCD_RETURNVAL); + } + TK_NextToken(); + } +} + +//========================================================================== +// +// EvalConstExpression +// +//========================================================================== + +static int EvalConstExpression(void) +{ + pa_ConstExprIsString = NO; // Used by PC_PutMapVariable + ExprStackIndex = 0; + ConstantExpression = YES; + ExprLevA(); + if(ExprStackIndex != 1) + { + ERR_Error(ERR_BAD_CONST_EXPR, YES, NULL); + ExprStack[0] = 0; + ExprStackIndex = 1; + } + return PopExStk(); +} + +//========================================================================== +// +// EvalExpression +// +// [RH] Rewrote all the ExprLevA - ExprLevJ functions in favor of a single +// table-driven parser function. +// +//========================================================================== + +static void EvalExpression(void) +{ + ConstantExpression = NO; + ExprLevA(); +} + +static void ExprLevA(void) +{ + ExprLevX(0); +} + +// Operator precedence levels: +// Operator: ? : +// Operator: || +// Operator: && +// Operator: | +// Operator: ^ +// Operator: & +// Operators: == != +// Operators: < <= > >= +// Operators: << >> +// Operators: + - +// Operators: * / % + +static void ExprLevX(int level) +{ + if(OpsList[level] == NULL) + { + boolean unaryMinus; + + unaryMinus = FALSE; + if(tk_Token == TK_MINUS) + { + unaryMinus = TRUE; + TK_NextToken(); + } + if(tk_Token == TK_PLUS) + { + // Completely ignore unary plus + TK_NextToken(); + } + if(ConstantExpression == YES) + { + ConstExprFactor(); + } + else + { + ExprFactor(); + } + if(unaryMinus == TRUE) + { + SendExprCommand(PCD_UNARYMINUS); + } + } + else + { + ExprLevX(level + 1); + while(TK_Member(OpsList[level])) + { + if (tk_Token == TK_TERNARY) + { + ExprTernary(); + } + else + { + tokenType_t token = tk_Token; + TK_NextToken(); + ExprLevX(level + 1); + SendExprCommand(TokenToPCD(token)); + } + } + } +} + +static void ExprLineSpecial(void) +{ + int argCountMin = tk_SpecialArgCount & 0xffff; + int argCountMax = tk_SpecialArgCount >> 16; + int specialValue = tk_SpecialValue; + + // There are two ways to use a special in an expression: + // 1. The special name by itself returns the special's number. + // 2. The special followed by parameters actually executes the special. + TK_NextToken(); + if(tk_Token != TK_LPAREN) + { + PC_AppendPushVal(specialValue); + } + else + { + int argCount = 0; + + TK_NextToken(); + if(tk_Token != TK_RPAREN) + { + TK_Undo(); + do + { + TK_NextToken(); + EvalExpression(); + argCount++; + } while(tk_Token == TK_COMMA); + } + if(argCount < argCountMin || argCount > argCountMax) + { + ERR_Error(specialValue >=0? ERR_BAD_LSPEC_ARG_COUNT : ERR_BAD_ARG_COUNT, YES); + return; + } + if (specialValue >= 0) + { + for(; argCount < 5; ++argCount) + { + PC_AppendPushVal(0); + } + TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN); + TK_NextToken(); + PC_AppendCmd(specialValue <= 255? PCD_LSPEC5RESULT : PCD_LSPEC5EXRESULT); + if(pc_NoShrink || specialValue > 255) + { + PC_AppendInt(specialValue); + } + else + { + PC_AppendByte((U_BYTE)specialValue); + } + } + else + { + TK_TokenMustBe(TK_RPAREN, ERR_MISSING_RPAREN); + TK_NextToken(); + PC_AppendCmd(PCD_CALLFUNC); + if(pc_NoShrink) + { + PC_AppendInt(argCount); + PC_AppendInt(-specialValue); + } + else + { + PC_AppendByte((U_BYTE)argCount); + PC_AppendWord((U_WORD)-specialValue); + } + } + } +} + +static void ExprTernary(void) +{ + int jumpAddrPtr; + + PC_AppendCmd(PCD_IFNOTGOTO); + jumpAddrPtr = pc_Address; + PC_SkipInt(); + + TK_NextToken(); + ExprLevA(); + + if(tk_Token != TK_COLON) + { + ERR_Error(ERR_BAD_EXPR, YES, NULL); + } + else + { + PC_AppendCmd(PCD_GOTO); + PC_WriteInt(pc_Address + 4, jumpAddrPtr); // int = 4 bytes + jumpAddrPtr = pc_Address; + PC_SkipInt(); + + TK_NextToken(); + ExprLevA(); + + PC_WriteInt(pc_Address, jumpAddrPtr); + } + +} + +static void ExprFactor(void) +{ + symbolNode_t *sym; + tokenType_t opToken; + + switch(tk_Token) + { + case TK_STRING: + if (ImportMode != IMPORT_Importing) + { + tk_Number = STR_Find(tk_String); + PC_AppendPushVal(tk_Number); + if (ImportMode == IMPORT_Exporting) + { + // The VM identifies strings by storing a library ID in the + // high word of the string index. The library ID is not + // known until the script actually gets loaded into the game, + // so we need to use this p-code to tack the ID of the + // currently running library to the index of the string that + // just got pushed onto the stack. + // + // Simply assuming that a string is from the current library + // is not good enough, because they can be passed around + // between libraries and the map's behavior. Thus, we need + // to know which object file a particular string belongs to. + // + // A specific example: + // A map's behavior calls a function in a library and passes + // a string: + // + // LibFunc ("The library will do something with this string."); + // + // The library function needs to know that the string originated + // outside the library. Similarly, if a library function returns + // a string, the caller needs to know that the string did not + // originate from the same object file. + // + // And that's why strings have library IDs tacked onto them. + // The map's main behavior (i.e. an object that is not a library) + // always uses library ID 0 to identify its strings, so its + // strings don't need to be tagged. + PC_AppendCmd(PCD_TAGSTRING); + } + } + TK_NextToken(); + break; + case TK_NUMBER: + PC_AppendPushVal(tk_Number); + TK_NextToken(); + break; + case TK_LPAREN: + TK_NextToken(); + ExprLevA(); + if(tk_Token != TK_RPAREN) + { + ERR_Error(ERR_BAD_EXPR, YES, NULL); + TK_SkipPast(TK_RPAREN); + } + else + { + TK_NextToken(); + } + break; + case TK_NOT: + TK_NextToken(); + ExprFactor(); + PC_AppendCmd(PCD_NEGATELOGICAL); + break; + case TK_TILDE: + TK_NextToken(); + ExprFactor(); + PC_AppendCmd(PCD_NEGATEBINARY); + break; + case TK_INC: + case TK_DEC: + opToken = tk_Token; + TK_NextTokenMustBe(TK_IDENTIFIER, ERR_INCDEC_OP_ON_NON_VAR); + sym = DemandSymbol(tk_String); + if(sym->type != SY_SCRIPTVAR && sym->type != SY_MAPVAR + && sym->type != SY_WORLDVAR && sym->type != SY_GLOBALVAR + && sym->type != SY_MAPARRAY && sym->type != SY_WORLDARRAY + && sym->type != SY_GLOBALARRAY && sym->type != SY_SCRIPTARRAY) + { + ERR_Error(ERR_INCDEC_OP_ON_NON_VAR, YES); + } + else + { + TK_NextToken(); + if(sym->type == SY_MAPARRAY || sym->type == SY_WORLDARRAY + || sym->type == SY_GLOBALARRAY || sym->type == SY_SCRIPTARRAY) + { + ParseArrayIndices(sym, sym->info.array.ndim); + PC_AppendCmd(PCD_DUP); + } + else if(tk_Token == TK_LBRACKET) + { + ERR_Error(ERR_NOT_AN_ARRAY, YES, sym->name); + while(tk_Token == TK_LBRACKET) + { + TK_SkipPast(TK_RBRACKET); + } + } + PC_AppendCmd(GetIncDecPCD(opToken, sym->type)); + PC_AppendShrink(sym->info.var.index); + PC_AppendCmd(GetPushVarPCD(sym->type)); + PC_AppendShrink(sym->info.var.index); + } + break; + case TK_IDENTIFIER: + sym = SpeculateSymbol(tk_String, YES); + switch(sym->type) + { + case SY_SCRIPTALIAS: + // FIXME + break; + case SY_SCRIPTARRAY: + case SY_MAPARRAY: + case SY_WORLDARRAY: + case SY_GLOBALARRAY: + TK_NextToken(); + ParseArrayIndices(sym, sym->info.array.ndim); + // fallthrough + case SY_SCRIPTVAR: + case SY_MAPVAR: + case SY_WORLDVAR: + case SY_GLOBALVAR: + if(sym->type != SY_MAPARRAY && sym->type != SY_WORLDARRAY + && sym->type != SY_GLOBALARRAY && sym->type != SY_SCRIPTARRAY) + { + TK_NextToken(); + if(tk_Token == TK_LBRACKET) + { + ERR_Error(ERR_NOT_AN_ARRAY, YES, sym->name); + while(tk_Token == TK_LBRACKET) + { + TK_SkipPast(TK_RBRACKET); + } + } + } + if((tk_Token == TK_INC || tk_Token == TK_DEC) + && (sym->type == SY_MAPARRAY || sym->type == SY_WORLDARRAY + || sym->type == SY_GLOBALARRAY || sym->type == SY_SCRIPTARRAY)) + { + PC_AppendCmd(PCD_DUP); + } + PC_AppendCmd(GetPushVarPCD(sym->type)); + PC_AppendShrink(sym->info.var.index); + if(tk_Token == TK_INC || tk_Token == TK_DEC) + { + if(sym->type == SY_MAPARRAY || sym->type == SY_WORLDARRAY + || sym->type == SY_GLOBALARRAY || sym->type == SY_SCRIPTARRAY) + { + PC_AppendCmd(PCD_SWAP); + } + PC_AppendCmd(GetIncDecPCD(tk_Token, sym->type)); + PC_AppendShrink(sym->info.var.index); + TK_NextToken(); + } + break; + case SY_INTERNFUNC: + if(sym->info.internFunc.hasReturnValue == NO) + { + ERR_Error(ERR_EXPR_FUNC_NO_RET_VAL, YES); + } + ProcessInternFunc(sym); + break; + case SY_SCRIPTFUNC: + if(sym->info.scriptFunc.predefined == NO + && sym->info.scriptFunc.hasReturnValue == NO) + { + ERR_Error(ERR_EXPR_FUNC_NO_RET_VAL, YES); + } + ProcessScriptFunc(sym, NO); + break; + default: + ERR_Error(ERR_ILLEGAL_EXPR_IDENT, YES, tk_String); + TK_NextToken(); + break; + } + break; + case TK_LINESPECIAL: + ExprLineSpecial(); + break; + case TK_STRPARAM_EVAL: + LeadingPrint(); + TK_NextToken(); + break; + case TK_STRCPY: + LeadingStrcpy(); + TK_NextToken(); + break; + case TK_MORPHACTOR: + LeadingMorphActor(); + TK_NextToken(); + break; + default: + ERR_Error(ERR_BAD_EXPR, YES); + TK_NextToken(); + break; + } +} + +static void ConstExprFactor(void) +{ + switch(tk_Token) + { + case TK_STRING: + if (ImportMode != IMPORT_Importing) + { + int strnum = STR_Find(tk_String); + if (ImportMode == IMPORT_Exporting) + { + pa_ConstExprIsString = YES; + } + PushExStk(strnum); + } + else + { + // Importing, so it doesn't matter + PushExStk(0); + } + TK_NextToken(); + break; + case TK_NUMBER: + PushExStk(tk_Number); + TK_NextToken(); + break; + case TK_LPAREN: + TK_NextToken(); + ExprLevA(); + if(tk_Token != TK_RPAREN) + { + ERR_Error(ERR_BAD_CONST_EXPR, YES); + TK_SkipPast(TK_RPAREN); + } + else + { + TK_NextToken(); + } + break; + case TK_NOT: + TK_NextToken(); + ConstExprFactor(); + SendExprCommand(PCD_NEGATELOGICAL); + break; + case TK_TILDE: + TK_NextToken(); + ConstExprFactor(); + SendExprCommand(PCD_NEGATEBINARY); + break; + default: + ERR_Error(ERR_BAD_CONST_EXPR, YES); + PushExStk(0); + while(tk_Token != TK_COMMA && + tk_Token != TK_SEMICOLON && + tk_Token != TK_RPAREN) + { + if(tk_Token == TK_EOF) + { + ERR_Exit(ERR_EOF, YES); + } + TK_NextToken(); + } + break; + } +} + +//========================================================================== +// +// SendExprCommand +// +//========================================================================== + +static void SendExprCommand(pcd_t pcd) +{ + int operand1, operand2; + + if(ConstantExpression == NO) + { + PC_AppendCmd(pcd); + return; + } + switch(pcd) + { + case PCD_ADD: + PushExStk(PopExStk()+PopExStk()); + break; + case PCD_SUBTRACT: + operand2 = PopExStk(); + PushExStk(PopExStk()-operand2); + break; + case PCD_MULTIPLY: + PushExStk(PopExStk()*PopExStk()); + break; + case PCD_DIVIDE: + case PCD_MODULUS: + operand2 = PopExStk(); + operand1 = PopExStk(); + if (operand2 != 0) + { + PushExStk(pcd == PCD_DIVIDE ? operand1/operand2 : operand1%operand2); + } + else + { + ERR_Error(ERR_DIV_BY_ZERO_IN_CONST_EXPR, YES); + PushExStk(operand1); + } + break; + case PCD_EQ: + PushExStk(PopExStk() == PopExStk()); + break; + case PCD_NE: + PushExStk(PopExStk() != PopExStk()); + break; + case PCD_LT: + operand2 = PopExStk(); + PushExStk(PopExStk() < operand2); + break; + case PCD_GT: + operand2 = PopExStk(); + PushExStk(PopExStk() > operand2); + break; + case PCD_LE: + operand2 = PopExStk(); + PushExStk(PopExStk() <= operand2); + break; + case PCD_GE: + operand2 = PopExStk(); + PushExStk(PopExStk() >= operand2); + break; + case PCD_ANDLOGICAL: + operand2 = PopExStk(); + operand1 = PopExStk(); + PushExStk(operand1 && operand2); + break; + case PCD_ORLOGICAL: + operand2 = PopExStk(); + operand1 = PopExStk(); + PushExStk(operand1 || operand2); + break; + case PCD_ANDBITWISE: + PushExStk(PopExStk()&PopExStk()); + break; + case PCD_ORBITWISE: + PushExStk(PopExStk()|PopExStk()); + break; + case PCD_EORBITWISE: + PushExStk(PopExStk()^PopExStk()); + break; + case PCD_NEGATELOGICAL: + PushExStk(!PopExStk()); + break; + case PCD_NEGATEBINARY: + PushExStk(~PopExStk()); + break; + case PCD_LSHIFT: + operand2 = PopExStk(); + PushExStk(PopExStk()<>operand2); + break; + case PCD_UNARYMINUS: + PushExStk(-PopExStk()); + break; + default: + ERR_Exit(ERR_UNKNOWN_CONST_EXPR_PCD, YES); + break; + } +} + +//========================================================================== +// +// PushExStk +// +//========================================================================== + +static void PushExStk(int value) +{ + if(ExprStackIndex == EXPR_STACK_DEPTH) + { + ERR_Exit(ERR_EXPR_STACK_OVERFLOW, YES); + } + ExprStack[ExprStackIndex++] = value; +} + +//========================================================================== +// +// PopExStk +// +//========================================================================== + +static int PopExStk(void) +{ + if(ExprStackIndex < 1) + { + ERR_Error(ERR_EXPR_STACK_EMPTY, YES); + return 0; + } + return ExprStack[--ExprStackIndex]; +} + +//========================================================================== +// +// TokenToPCD +// +//========================================================================== + +static pcd_t TokenToPCD(tokenType_t token) +{ + int i; + static struct + { + tokenType_t token; + pcd_t pcd; + } operatorLookup[] = + { + { TK_ORLOGICAL, PCD_ORLOGICAL }, + { TK_ANDLOGICAL, PCD_ANDLOGICAL }, + { TK_ORBITWISE, PCD_ORBITWISE }, + { TK_EORBITWISE, PCD_EORBITWISE }, + { TK_ANDBITWISE, PCD_ANDBITWISE }, + { TK_EQ, PCD_EQ }, + { TK_NE, PCD_NE }, + { TK_LT, PCD_LT }, + { TK_LE, PCD_LE }, + { TK_GT, PCD_GT }, + { TK_GE, PCD_GE }, + { TK_LSHIFT, PCD_LSHIFT }, + { TK_RSHIFT, PCD_RSHIFT }, + { TK_PLUS, PCD_ADD }, + { TK_MINUS, PCD_SUBTRACT }, + { TK_ASTERISK, PCD_MULTIPLY }, + { TK_SLASH, PCD_DIVIDE }, + { TK_PERCENT, PCD_MODULUS }, + { TK_NONE, PCD_NOP } + }; + + for(i = 0; operatorLookup[i].token != TK_NONE; i++) + { + if(operatorLookup[i].token == token) + { + return operatorLookup[i].pcd; + } + } + return PCD_NOP; +} + +//========================================================================== +// +// GetPushVarPCD +// +//========================================================================== + +static pcd_t GetPushVarPCD(symbolType_t symType) +{ + switch(symType) + { + case SY_SCRIPTVAR: + return PCD_PUSHSCRIPTVAR; + case SY_MAPVAR: + return PCD_PUSHMAPVAR; + case SY_WORLDVAR: + return PCD_PUSHWORLDVAR; + case SY_GLOBALVAR: + return PCD_PUSHGLOBALVAR; + case SY_SCRIPTARRAY: + return PCD_PUSHSCRIPTARRAY; + case SY_MAPARRAY: + return PCD_PUSHMAPARRAY; + case SY_WORLDARRAY: + return PCD_PUSHWORLDARRAY; + case SY_GLOBALARRAY: + return PCD_PUSHGLOBALARRAY; + default: + break; + } + return PCD_NOP; +} + +//========================================================================== +// +// GetIncDecPCD +// +//========================================================================== + +static pcd_t GetIncDecPCD(tokenType_t token, symbolType_t symbol) +{ + int i; + static struct + { + tokenType_t token; + symbolType_t symbol; + pcd_t pcd; + } incDecLookup[] = + { + { TK_INC, SY_SCRIPTVAR, PCD_INCSCRIPTVAR }, + { TK_INC, SY_MAPVAR, PCD_INCMAPVAR }, + { TK_INC, SY_WORLDVAR, PCD_INCWORLDVAR }, + { TK_INC, SY_GLOBALVAR, PCD_INCGLOBALVAR }, + { TK_INC, SY_SCRIPTARRAY, PCD_INCSCRIPTARRAY }, + { TK_INC, SY_MAPARRAY, PCD_INCMAPARRAY }, + { TK_INC, SY_WORLDARRAY, PCD_INCWORLDARRAY }, + { TK_INC, SY_GLOBALARRAY, PCD_INCGLOBALARRAY }, + + { TK_DEC, SY_SCRIPTVAR, PCD_DECSCRIPTVAR }, + { TK_DEC, SY_MAPVAR, PCD_DECMAPVAR }, + { TK_DEC, SY_WORLDVAR, PCD_DECWORLDVAR }, + { TK_DEC, SY_GLOBALVAR, PCD_DECGLOBALVAR }, + { TK_DEC, SY_SCRIPTARRAY, PCD_DECSCRIPTARRAY }, + { TK_DEC, SY_MAPARRAY, PCD_DECMAPARRAY }, + { TK_DEC, SY_WORLDARRAY, PCD_DECWORLDARRAY }, + { TK_DEC, SY_GLOBALARRAY, PCD_DECGLOBALARRAY }, + + { TK_NONE, SY_DUMMY, PCD_NOP } + }; + + for(i = 0; incDecLookup[i].token != TK_NONE; i++) + { + if(incDecLookup[i].token == token + && incDecLookup[i].symbol == symbol) + { + return incDecLookup[i].pcd; + } + } + return PCD_NOP; +} + +//========================================================================== +// +// ParseArrayDims +// +//========================================================================== + +static void ParseArrayDims(int *size_p, int *ndim_p, int dims[MAX_ARRAY_DIMS]) +{ + int size = 0; + int ndim = 0; + memset(dims, 0, MAX_ARRAY_DIMS*sizeof(dims[0])); + + while(tk_Token == TK_LBRACKET) + { + if(ndim == MAX_ARRAY_DIMS) + { + ERR_Error(ERR_TOO_MANY_ARRAY_DIMS, YES); + do + { + TK_NextToken(); + } while(tk_Token != TK_COMMA && tk_Token != TK_SEMICOLON); + break; + } + TK_NextToken(); + if (tk_Token == TK_RBRACKET) + { + ERR_Error(ERR_NEED_ARRAY_SIZE, YES); + } + else + { + dims[ndim] = EvalConstExpression(); + if(dims[ndim] == 0) + { + ERR_Error(ERR_ZERO_DIMENSION, YES); + dims[ndim] = 1; + } + if(ndim == 0) + { + size = dims[ndim]; + } + else + { + size *= dims[ndim]; + } + } + ndim++; + TK_TokenMustBe(TK_RBRACKET, ERR_MISSING_RBRACKET); + TK_NextToken(); + } + if(pc_EnforceHexen) + { + TK_Undo(); // backup so error pointer is on last bracket instead of following token + ERR_Error(ERR_HEXEN_COMPAT, YES); + TK_NextToken(); + } + *size_p = size; + *ndim_p = ndim; +} + +static void SymToArray(int symtype, symbolNode_t *sym, int index, int size, int ndim, int dims[MAX_ARRAY_DIMS]) +{ + int i; + + MS_Message(MSG_DEBUG, "%s changed to an array of size %d\n", sym->name, size); + sym->type = symtype; + sym->info.array.index = index; + sym->info.array.ndim = ndim; + sym->info.array.size = size; + if(ndim > 0) + { + sym->info.array.dimensions[ndim-1] = 1; + for(i = ndim - 2; i >= 0; --i) + { + sym->info.array.dimensions[i] = + sym->info.array.dimensions[i+1] * dims[i+1]; + } + } + MS_Message(MSG_DEBUG, " - with multipliers "); + for(i = 0; i < ndim; ++i) + { + MS_Message(MSG_DEBUG, "[%d]", sym->info.array.dimensions[i]); + } + MS_Message(MSG_DEBUG, "\n"); +} + +//========================================================================== +// +// ParseArrayIndices +// +//========================================================================== + +static void ParseArrayIndices(symbolNode_t *sym, int requiredIndices) +{ + boolean warned = NO; + int i; + + if(requiredIndices > 0) + { + TK_TokenMustBe(TK_LBRACKET, ERR_MISSING_LBRACKET); + } + i = 0; + while(tk_Token == TK_LBRACKET) + { + TK_NextToken(); + if(((sym->type == SY_MAPARRAY || sym->type == SY_SCRIPTARRAY) && i == requiredIndices) || + (sym->type != SY_MAPARRAY && sym->type != SY_SCRIPTARRAY && i > 0)) + { + if (!warned) + { + warned = YES; + if(sym->info.array.ndim == requiredIndices) + { + ERR_Error(ERR_TOO_MANY_DIM_USED, YES, + sym->name, sym->info.array.ndim); + } + else + { + ERR_Error(ERR_NOT_A_CHAR_ARRAY, YES, sym->name, + sym->info.array.ndim, requiredIndices); + } + } + } + EvalExpression(); + if(i < sym->info.array.ndim - 1 && sym->info.array.dimensions[i] > 1) + { + PC_AppendPushVal(sym->info.array.dimensions[i]); + PC_AppendCmd(PCD_MULTIPLY); + } + if(i > 0) + { + PC_AppendCmd(PCD_ADD); + } + i++; + TK_TokenMustBe(TK_RBRACKET, ERR_MISSING_RBRACKET); + TK_NextToken(); + } + if(i < requiredIndices) + { + ERR_Error(ERR_TOO_FEW_DIM_USED, YES, + sym->name, requiredIndices - i); + } + // if there were unspecified indices, multiply the offset by their sizes [JB] + if(requiredIndices < sym->info.array.ndim - 1) + { + int i, mult = 1; + for(i = 0; i < sym->info.array.ndim - requiredIndices - 1; ++i) + { + mult *= sym->info.array.dimensions[sym->info.array.ndim - 2 - i]; + } + if(mult > 1) + { + PC_AppendPushVal(mult); + PC_AppendCmd(PCD_MULTIPLY); + } + } +} + +//========================================================================== +// +// ProcessArrayLevel +// +//========================================================================== + +static void ProcessArrayLevel(int level, int *entry, int ndim, + int dims[MAX_ARRAY_DIMS], int muls[MAX_ARRAY_DIMS], char *name) +{ + int warned_too_many = NO; + int i; + + for(i = 0; ; ++i) + { + if(tk_Token == TK_COMMA) + { + entry += muls[level-1]; + TK_NextToken(); + } + else if(tk_Token == TK_RBRACE) + { + TK_NextToken(); + return; + } + else + { + if(level == ndim) + { + if(tk_Token == TK_LBRACE) + { + ERR_Error(ERR_TOO_MANY_DIM_USED, YES, name, ndim); + SkipBraceBlock(0); + TK_NextToken(); + entry++; + } + else + { + int val; + + if (i >= dims[level - 1] && !warned_too_many) + { + warned_too_many = YES; + ERR_Error(ERR_TOO_MANY_ARRAY_INIT, YES); + } + val = EvalConstExpression(); + ArrayHasStrings |= pa_ConstExprIsString; + if (i < dims[level - 1]) + { + entry[i] = val; + } + } + } + else + { + //Bugfix for r3226 by Zom-B + if (i >= dims[level - 1]) + { + if (!warned_too_many) + { + warned_too_many = YES; + ERR_Error(ERR_TOO_MANY_ARRAY_INIT, YES); + } + // Allow execution to continue without stray memory access + entry -= muls[level-1]; + } + TK_TokenMustBe(TK_LBRACE, ERR_MISSING_LBRACE_ARR); + TK_NextToken(); + ProcessArrayLevel(level+1, entry, ndim, dims, muls, name); + assert(level > 0); + entry += muls[level-1]; + } + if(i < dims[level-1]-1) + { + if(tk_Token != TK_RBRACE) + { + TK_TokenMustBe(TK_COMMA, ERR_MISSING_COMMA); + TK_NextToken(); + } + } + else + { + if(tk_Token != TK_COMMA) + { + TK_TokenMustBe(TK_RBRACE, ERR_MISSING_RBRACE_ARR); + } + else + { + TK_NextToken(); + } + } + } + } + TK_TokenMustBe(TK_RBRACE, ERR_MISSING_RBRACE_ARR); + TK_NextToken(); +} + +//========================================================================== +// +// InitializeArray +// +//========================================================================== + +static void InitializeArray(symbolNode_t *sym, int dims[MAX_ARRAY_DIMS], int size) +{ + static int *entries = NULL; + static int lastsize = -1; + + if(lastsize < size) + { + entries = MS_Realloc(entries, sizeof(int)*size, ERR_OUT_OF_MEMORY); + lastsize = size; + } + memset(entries, 0, sizeof(int)*size); + + TK_NextTokenMustBe(TK_LBRACE, ERR_MISSING_LBRACE_ARR); + TK_NextToken(); + ArrayHasStrings = NO; + ProcessArrayLevel(1, entries, sym->info.array.ndim, dims, + sym->info.array.dimensions, sym->name); + if(ImportMode != IMPORT_Importing) + { + PC_InitArray(sym->info.array.index, entries, ArrayHasStrings); + } +} + +//========================================================================== +// +// ProcessScriptArrayLevel +// +//========================================================================== + +static void ProcessScriptArrayLevel(int level, int loc, symbolNode_t *sym, int ndim, + int dims[MAX_ARRAY_DIMS], int muls[MAX_ARRAY_DIMS], char *name) +{ + int warned_too_many = NO; + int i; + + for(i = 0; ; ++i) + { + if(tk_Token == TK_COMMA) + { + loc += muls[level-1]; + TK_NextToken(); + } + else if(tk_Token == TK_RBRACE) + { + TK_NextToken(); + return; + } + else + { + if(level == ndim) + { + if(tk_Token == TK_LBRACE) + { + ERR_Error(ERR_TOO_MANY_DIM_USED, YES, name, ndim); + SkipBraceBlock(0); + TK_NextToken(); + loc++; + } + else + { + if(i >= dims[level - 1] && !warned_too_many) + { + warned_too_many = YES; + ERR_Error(ERR_TOO_MANY_ARRAY_INIT, YES); + } + PC_AppendPushVal(loc + i); + EvalExpression(); + PC_AppendCmd(PCD_ASSIGNSCRIPTARRAY); + PC_AppendShrink(sym->info.array.index); + } + } + else + { + //Bugfix for r3226 by Zom-B + if (i >= dims[level - 1]) + { + if (!warned_too_many) + { + warned_too_many = YES; + ERR_Error(ERR_TOO_MANY_ARRAY_INIT, YES); + } + } + TK_TokenMustBe(TK_LBRACE, ERR_MISSING_LBRACE_ARR); + TK_NextToken(); + ProcessScriptArrayLevel(level+1, loc, sym, ndim, dims, muls, name); + assert(level > 0); + loc += muls[level-1]; + } + if(i < dims[level-1]-1) + { + if(tk_Token != TK_RBRACE) + { + TK_TokenMustBe(TK_COMMA, ERR_MISSING_COMMA); + TK_NextToken(); + } + } + else + { + if(tk_Token != TK_COMMA) + { + TK_TokenMustBe(TK_RBRACE, ERR_MISSING_RBRACE_ARR); + } + else + { + TK_NextToken(); + } + } + } + } + TK_TokenMustBe(TK_RBRACE, ERR_MISSING_RBRACE_ARR); + TK_NextToken(); +} + +//========================================================================== +// +// InitializeScriptArray +// +//========================================================================== + +static void InitializeScriptArray(symbolNode_t *sym, int dims[MAX_ARRAY_DIMS]) +{ + TK_NextTokenMustBe(TK_LBRACE, ERR_MISSING_LBRACE_ARR); + TK_NextToken(); + ArrayHasStrings = NO; + ProcessScriptArrayLevel(1, 0, sym, sym->info.array.ndim, dims, + sym->info.array.dimensions, sym->name); +} + +//========================================================================== +// +// DemandSymbol +// +//========================================================================== + +static symbolNode_t *DemandSymbol(char *name) +{ + symbolNode_t *sym; + + if((sym = SY_Find(name)) == NULL) + { + ERR_Exit(ERR_UNKNOWN_IDENTIFIER, YES, name); + } + return sym; +} + +//========================================================================== +// +// SpeculateSymbol +// +//========================================================================== + +static symbolNode_t *SpeculateSymbol(char *name, boolean hasReturn) +{ + symbolNode_t *sym; + + sym = SY_Find(name); + if(sym == NULL) + { + char name[MAX_IDENTIFIER_LENGTH]; + + strcpy (name, tk_String); + TK_NextToken(); + if(tk_Token == TK_LPAREN) + { // Looks like a function call + sym = SpeculateFunction(name, hasReturn); + TK_Undo(); + } + else + { + ERR_Exit(ERR_UNKNOWN_IDENTIFIER, YES, name); + } + } + return sym; +} + +//========================================================================== +// +// SpeculateFunction +// +// Add a temporary symbol for a function that is used before it is defined. +// +//========================================================================== + +static symbolNode_t *SpeculateFunction(const char *name, boolean hasReturn) +{ + symbolNode_t *sym; + + MS_Message(MSG_DEBUG, "---- SpeculateFunction %s ----\n", name); + sym = SY_InsertGlobal(tk_String, SY_SCRIPTFUNC); + sym->info.scriptFunc.predefined = YES; + sym->info.scriptFunc.hasReturnValue = hasReturn; + sym->info.scriptFunc.sourceLine = tk_Line; + sym->info.scriptFunc.sourceName = tk_SourceName; + sym->info.scriptFunc.argCount = -1; + sym->info.scriptFunc.funcNumber = 0; + return sym; +} + +//========================================================================== +// +// UnspeculateFunction +// +// Fills in function calls that were made before this function was defined. +// +//========================================================================== + +static void UnspeculateFunction(symbolNode_t *sym) +{ + prefunc_t *fillin; + prefunc_t **prev; + + prev = &FillinFunctions; + fillin = FillinFunctions; + while(fillin != NULL) + { + prefunc_t *next = fillin->next; + if(fillin->sym == sym) + { + if(fillin->argcount != sym->info.scriptFunc.argCount) + { + ERR_ErrorAt(fillin->source, fillin->line); + ERR_Error(ERR_FUNC_ARGUMENT_COUNT, YES, sym->name, + sym->info.scriptFunc.argCount, + sym->info.scriptFunc.argCount == 1 ? "" : "s"); + } + + if(pc_NoShrink) + { + PC_WriteInt(sym->info.scriptFunc.funcNumber, fillin->address); + } + else + { + PC_WriteByte((U_BYTE)sym->info.scriptFunc.funcNumber, fillin->address); + } + if(FillinFunctionsLatest == &fillin->next) + { + FillinFunctionsLatest = prev; + } + free (fillin); + *prev = next; + } + else + { + prev = &fillin->next; + } + fillin = next; + } +} + +//========================================================================== +// +// AddScriptFuncRef +// +//========================================================================== + +static void AddScriptFuncRef(symbolNode_t *sym, int address, int argcount) +{ + prefunc_t *fillin = MS_Alloc(sizeof(*fillin), ERR_OUT_OF_MEMORY); + fillin->next = NULL; + fillin->sym = sym; + fillin->address = address; + fillin->argcount = argcount; + fillin->line = tk_Line; + fillin->source = tk_SourceName; + *FillinFunctionsLatest = fillin; + FillinFunctionsLatest = &fillin->next; +} + +//========================================================================== +// +// Check for undefined functions +// +//========================================================================== + +static void CheckForUndefinedFunctions(void) +{ + prefunc_t *fillin = FillinFunctions; + + while(fillin != NULL) + { + ERR_ErrorAt(fillin->source, fillin->line); + ERR_Error(ERR_UNDEFINED_FUNC, YES, fillin->sym->name); + fillin = fillin->next; + } +} + +//========================================================================== +// +// SkipBraceBlock +// +// If depth is 0, it scans for the first { and then starts going from there. +// At exit, the terminating } is left as the current token. +// +//========================================================================== + +void SkipBraceBlock(int depth) +{ + if (depth == 0) + { + // Find first { + while(tk_Token != TK_LBRACE) + { + if(tk_Token == TK_EOF) + { + ERR_Exit(ERR_EOF, YES, NULL); + } + TK_NextToken(); + } + depth = 1; + } + // Match it with a } + do + { + TK_NextToken(); + if(tk_Token == TK_EOF) + { + ERR_Exit(ERR_EOF, YES, NULL); + } + else if (tk_Token == TK_LBRACE) + { + depth++; + } + else if (tk_Token == TK_RBRACE) + { + depth--; + } + } while (depth > 0); +} diff --git a/parse.h b/parse.h index 23294de..d601ca5 100644 --- a/parse.h +++ b/parse.h @@ -1,41 +1,41 @@ - -//************************************************************************** -//** -//** parse.h -//** -//************************************************************************** - -#ifndef __PARSE_H__ -#define __PARSE_H__ - -// HEADER FILES ------------------------------------------------------------ - -// MACROS ------------------------------------------------------------------ - -// TYPES ------------------------------------------------------------------- - -struct ScriptTypes -{ - const char *TypeName; - int TypeBase; - int TypeCount; -}; - -// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- - -void PA_Parse(void); - -// PUBLIC DATA DECLARATIONS ------------------------------------------------ - -extern int pa_ScriptCount; -extern struct ScriptTypes *pa_TypedScriptCounts; -extern int pa_MapVarCount; -extern int pa_WorldVarCount; -extern int pa_GlobalVarCount; -extern int pa_WorldArrayCount; -extern int pa_GlobalArrayCount; -extern enum ImportModes ImportMode; -extern boolean ExporterFlagged; -extern boolean pa_ConstExprIsString; - -#endif + +//************************************************************************** +//** +//** parse.h +//** +//************************************************************************** + +#ifndef __PARSE_H__ +#define __PARSE_H__ + +// HEADER FILES ------------------------------------------------------------ + +// MACROS ------------------------------------------------------------------ + +// TYPES ------------------------------------------------------------------- + +struct ScriptTypes +{ + const char *TypeName; + int TypeBase; + int TypeCount; +}; + +// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- + +void PA_Parse(void); + +// PUBLIC DATA DECLARATIONS ------------------------------------------------ + +extern int pa_ScriptCount; +extern struct ScriptTypes *pa_TypedScriptCounts; +extern int pa_MapVarCount; +extern int pa_WorldVarCount; +extern int pa_GlobalVarCount; +extern int pa_WorldArrayCount; +extern int pa_GlobalArrayCount; +extern enum ImportModes ImportMode; +extern boolean ExporterFlagged; +extern boolean pa_ConstExprIsString; + +#endif diff --git a/pcode.c b/pcode.c index a601ca6..d522950 100644 --- a/pcode.c +++ b/pcode.c @@ -1,1611 +1,1611 @@ - -//************************************************************************** -//** -//** pcode.c -//** -//************************************************************************** - -// HEADER FILES ------------------------------------------------------------ - -#include -#include -#include -#include -#include "pcode.h" -#include "common.h" -#include "error.h" -#include "misc.h" -#include "strlist.h" -#include "token.h" -#include "symbol.h" -#include "parse.h" - -// MACROS ------------------------------------------------------------------ - -// TYPES ------------------------------------------------------------------- - -typedef struct scriptInfo_s -{ - S_WORD number; - U_BYTE type; - U_BYTE argCount; - U_BYTE arrayCount; - U_WORD varCount; - U_WORD flags; - int address; - int srcLine; - boolean imported; - int arraySizes[MAX_SCRIPT_ARRAYS]; -} scriptInfo_t; - -typedef struct functionInfo_s -{ - U_BYTE hasReturnValue; - U_BYTE argCount; - U_BYTE localCount; - U_BYTE arrayCount; - int address; - int name; - int arraySizes[MAX_SCRIPT_ARRAYS]; -} functionInfo_t; - -typedef struct mapVarInfo_s -{ - int initializer; - boolean isString; - char *name; - boolean imported; -} mapVarInfo_t; - -// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- - -// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- - -// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- - -static void GrowBuffer(void); -static void Append(void *buffer, size_t size); -static void Write(void *buffer, size_t size, int address); -static void Skip(size_t size); -static void CloseOld(void); -static void CloseNew(void); -static void CreateDummyScripts(void); -static void RecordDummyScripts(void); - -// EXTERNAL DATA DECLARATIONS ---------------------------------------------- - -// PUBLIC DATA DEFINITIONS ------------------------------------------------- - -int pc_Address; -byte *pc_Buffer; -byte *pc_BufferPtr; -int pc_ScriptCount; -int pc_FunctionCount; -boolean pc_NoShrink; -boolean pc_HexenCase; -boolean pc_EnforceHexen; -boolean pc_WarnNotHexen; -boolean pc_WadAuthor = TRUE; -boolean pc_EncryptStrings; -int pc_LastAppendedCommand; -int pc_DummyAddress; - -// PRIVATE DATA DEFINITIONS ------------------------------------------------ - -static size_t BufferSize; -static boolean ObjectOpened = NO; -static scriptInfo_t ScriptInfo[MAX_SCRIPT_COUNT]; -static functionInfo_t FunctionInfo[MAX_FUNCTION_COUNT]; -static int ArraySizes[MAX_MAP_VARIABLES]; -static int *ArrayInits[MAX_MAP_VARIABLES]; -static boolean ArrayOfStrings[MAX_MAP_VARIABLES]; -static int NumArrays; -static mapVarInfo_t MapVariables[MAX_MAP_VARIABLES]; -static boolean MapVariablesInit = NO; -static char ObjectName[MAX_FILE_NAME_LENGTH]; -static int ObjectFlags; -static int PushByteAddr; -static char Imports[MAX_IMPORTS][9]; -static int NumImports; -static boolean HaveExtendedScripts; -static boolean HaveScriptArrays; - -static char *PCDNames[PCODE_COMMAND_COUNT] = -{ - "PCD_NOP", - "PCD_TERMINATE", - "PCD_SUSPEND", - "PCD_PUSHNUMBER", - "PCD_LSPEC1", - "PCD_LSPEC2", - "PCD_LSPEC3", - "PCD_LSPEC4", - "PCD_LSPEC5", - "PCD_LSPEC1DIRECT", - "PCD_LSPEC2DIRECT", - "PCD_LSPEC3DIRECT", - "PCD_LSPEC4DIRECT", - "PCD_LSPEC5DIRECT", - "PCD_ADD", - "PCD_SUBTRACT", - "PCD_MULTIPLY", - "PCD_DIVIDE", - "PCD_MODULUS", - "PCD_EQ", - "PCD_NE", - "PCD_LT", - "PCD_GT", - "PCD_LE", - "PCD_GE", - "PCD_ASSIGNSCRIPTVAR", - "PCD_ASSIGNMAPVAR", - "PCD_ASSIGNWORLDVAR", - "PCD_PUSHSCRIPTVAR", - "PCD_PUSHMAPVAR", - "PCD_PUSHWORLDVAR", - "PCD_ADDSCRIPTVAR", - "PCD_ADDMAPVAR", - "PCD_ADDWORLDVAR", - "PCD_SUBSCRIPTVAR", - "PCD_SUBMAPVAR", - "PCD_SUBWORLDVAR", - "PCD_MULSCRIPTVAR", - "PCD_MULMAPVAR", - "PCD_MULWORLDVAR", - "PCD_DIVSCRIPTVAR", - "PCD_DIVMAPVAR", - "PCD_DIVWORLDVAR", - "PCD_MODSCRIPTVAR", - "PCD_MODMAPVAR", - "PCD_MODWORLDVAR", - "PCD_INCSCRIPTVAR", - "PCD_INCMAPVAR", - "PCD_INCWORLDVAR", - "PCD_DECSCRIPTVAR", - "PCD_DECMAPVAR", - "PCD_DECWORLDVAR", - "PCD_GOTO", - "PCD_IFGOTO", - "PCD_DROP", - "PCD_DELAY", - "PCD_DELAYDIRECT", - "PCD_RANDOM", - "PCD_RANDOMDIRECT", - "PCD_THINGCOUNT", - "PCD_THINGCOUNTDIRECT", - "PCD_TAGWAIT", - "PCD_TAGWAITDIRECT", - "PCD_POLYWAIT", - "PCD_POLYWAITDIRECT", - "PCD_CHANGEFLOOR", - "PCD_CHANGEFLOORDIRECT", - "PCD_CHANGECEILING", - "PCD_CHANGECEILINGDIRECT", - "PCD_RESTART", - "PCD_ANDLOGICAL", - "PCD_ORLOGICAL", - "PCD_ANDBITWISE", - "PCD_ORBITWISE", - "PCD_EORBITWISE", - "PCD_NEGATELOGICAL", - "PCD_LSHIFT", - "PCD_RSHIFT", - "PCD_UNARYMINUS", - "PCD_IFNOTGOTO", - "PCD_LINESIDE", - "PCD_SCRIPTWAIT", - "PCD_SCRIPTWAITDIRECT", - "PCD_CLEARLINESPECIAL", - "PCD_CASEGOTO", - "PCD_BEGINPRINT", - "PCD_ENDPRINT", - "PCD_PRINTSTRING", - "PCD_PRINTNUMBER", - "PCD_PRINTCHARACTER", - "PCD_PLAYERCOUNT", - "PCD_GAMETYPE", - "PCD_GAMESKILL", - "PCD_TIMER", - "PCD_SECTORSOUND", - "PCD_AMBIENTSOUND", - "PCD_SOUNDSEQUENCE", - "PCD_SETLINETEXTURE", - "PCD_SETLINEBLOCKING", - "PCD_SETLINESPECIAL", - "PCD_THINGSOUND", - "PCD_ENDPRINTBOLD", -// [RH] End of Hexen p-codes - "PCD_ACTIVATORSOUND", - "PCD_LOCALAMBIENTSOUND", - "PCD_SETLINEMONSTERBLOCKING", -// [BC] Start of new pcodes - "PCD_PLAYERBLUESKULL", - "PCD_PLAYERREDSKULL", - "PCD_PLAYERYELLOWSKULL", - "PCD_PLAYERMASTERSKULL", - "PCD_PLAYERBLUECARD", - "PCD_PLAYERREDCARD", - "PCD_PLAYERYELLOWCARD", - "PCD_PLAYERMASTERCARD", - "PCD_PLAYERBLACKSKULL", - "PCD_PLAYERSILVERSKULL", - "PCD_PLAYERGOLDSKULL", - "PCD_PLAYERBLACKCARD", - "PCD_PLAYERSILVERCARD", - "PCD_ISNETWORKGAME", - "PCD_PLAYERTEAM", - "PCD_PLAYERHEALTH", - "PCD_PLAYERARMORPOINTS", - "PCD_PLAYERFRAGS", - "PCD_PLAYEREXPERT", - "PCD_BLUETEAMCOUNT", - "PCD_REDTEAMCOUNT", - "PCD_BLUETEAMSCORE", - "PCD_REDTEAMSCORE", - "PCD_ISONEFLAGCTF", - "PCD_LSPEC6", - "PCD_LSPEC6DIRECT", - "PCD_PRINTNAME", - "PCD_MUSICCHANGE", - "PCD_CONSOLECOMMANDDIRECT", - "PCD_CONSOLECOMMAND", - "PCD_SINGLEPLAYER", -// [RH] End of Skull Tag p-codes - "PCD_FIXEDMUL", - "PCD_FIXEDDIV", - "PCD_SETGRAVITY", - "PCD_SETGRAVITYDIRECT", - "PCD_SETAIRCONTROL", - "PCD_SETAIRCONTROLDIRECT", - "PCD_CLEARINVENTORY", - "PCD_GIVEINVENTORY", - "PCD_GIVEINVENTORYDIRECT", - "PCD_TAKEINVENTORY", - "PCD_TAKEINVENTORYDIRECT", - "PCD_CHECKINVENTORY", - "PCD_CHECKINVENTORYDIRECT", - "PCD_SPAWN", - "PCD_SPAWNDIRECT", - "PCD_SPAWNSPOT", - "PCD_SPAWNSPOTDIRECT", - "PCD_SETMUSIC", - "PCD_SETMUSICDIRECT", - "PCD_LOCALSETMUSIC", - "PCD_LOCALSETMUSICDIRECT", - "PCD_PRINTFIXED", - "PCD_PRINTLOCALIZED", - "PCD_MOREHUDMESSAGE", - "PCD_OPTHUDMESSAGE", - "PCD_ENDHUDMESSAGE", - "PCD_ENDHUDMESSAGEBOLD", - "PCD_SETSTYLE", - "PCD_SETSTYLEDIRECT", - "PCD_SETFONT", - "PCD_SETFONTDIRECT", - "PCD_PUSHBYTE", - "PCD_LSPEC1DIRECTB", - "PCD_LSPEC2DIRECTB", - "PCD_LSPEC3DIRECTB", - "PCD_LSPEC4DIRECTB", - "PCD_LSPEC5DIRECTB", - "PCD_DELAYDIRECTB", - "PCD_RANDOMDIRECTB", - "PCD_PUSHBYTES", - "PCD_PUSH2BYTES", - "PCD_PUSH3BYTES", - "PCD_PUSH4BYTES", - "PCD_PUSH5BYTES", - "PCD_SETTHINGSPECIAL", - "PCD_ASSIGNGLOBALVAR", - "PCD_PUSHGLOBALVAR", - "PCD_ADDGLOBALVAR", - "PCD_SUBGLOBALVAR", - "PCD_MULGLOBALVAR", - "PCD_DIVGLOBALVAR", - "PCD_MODGLOBALVAR", - "PCD_INCGLOBALVAR", - "PCD_DECGLOBALVAR", - "PCD_FADETO", - "PCD_FADERANGE", - "PCD_CANCELFADE", - "PCD_PLAYMOVIE", - "PCD_SETFLOORTRIGGER", - "PCD_SETCEILINGTRIGGER", - "PCD_GETACTORX", - "PCD_GETACTORY", - "PCD_GETACTORZ", - "PCD_STARTTRANSLATION", - "PCD_TRANSLATIONRANGE1", - "PCD_TRANSLATIONRANGE2", - "PCD_ENDTRANSLATION", - "PCD_CALL", - "PCD_CALLDISCARD", - "PCD_RETURNVOID", - "PCD_RETURNVAL", - "PCD_PUSHMAPARRAY", - "PCD_ASSIGNMAPARRAY", - "PCD_ADDMAPARRAY", - "PCD_SUBMAPARRAY", - "PCD_MULMAPARRAY", - "PCD_DIVMAPARRAY", - "PCD_MODMAPARRAY", - "PCD_INCMAPARRAY", - "PCD_DECMAPARRAY", - "PCD_DUP", - "PCD_SWAP", - "PCD_WRITETOINI", - "PCD_GETFROMINI", - "PCD_SIN", - "PCD_COS", - "PCD_VECTORANGLE", - "PCD_CHECKWEAPON", - "PCD_SETWEAPON", - "PCD_TAGSTRING", - "PCD_PUSHWORLDARRAY", - "PCD_ASSIGNWORLDARRAY", - "PCD_ADDWORLDARRAY", - "PCD_SUBWORLDARRAY", - "PCD_MULWORLDARRAY", - "PCD_DIVWORLDARRAY", - "PCD_MODWORLDARRAY", - "PCD_INCWORLDARRAY", - "PCD_DECWORLDARRAY", - "PCD_PUSHGLOBALARRAY", - "PCD_ASSIGNGLOBALARRAY", - "PCD_ADDGLOBALARRAY", - "PCD_SUBGLOBALARRAY", - "PCD_MULGLOBALARRAY", - "PCD_DIVGLOBALARRAY", - "PCD_MODGLOBALARRAY", - "PCD_INCGLOBALARRAY", - "PCD_DECGLOBALARRAY", - "PCD_SETMARINEWEAPON", - "PCD_SETACTORPROPERTY", - "PCD_GETACTORPROPERTY", - "PCD_PLAYERNUMBER", - "PCD_ACTIVATORTID", - "PCD_SETMARINESPRITE", - "PCD_GETSCREENWIDTH", - "PCD_GETSCREENHEIGHT", - "PCD_THING_PROJECTILE2", - "PCD_STRLEN", - "PCD_SETHUDSIZE", - "PCD_GETCVAR", - "PCD_CASEGOTOSORTED", - "PCD_SETRESULTVALUE", - "PCD_GETLINEROWOFFSET", - "PCD_GETACTORFLOORZ", - "PCD_GETACTORANGLE", - "PCD_GETSECTORFLOORZ", - "PCD_GETSECTORCEILINGZ", - "PCD_LSPEC5RESULT", - "PCD_GETSIGILPIECES", - "PCD_GELEVELINFO", - "PCD_CHANGESKY", - "PCD_PLAYERINGAME", - "PCD_PLAYERISBOT", - "PCD_SETCAMERATOTEXTURE", - "PCD_ENDLOG", - "PCD_GETAMMOCAPACITY", - "PCD_SETAMMOCAPACITY", -// [JB] start of new pcodes - "PCD_PRINTMAPCHARARRAY", - "PCD_PRINTWORLDCHARARRAY", - "PCD_PRINTGLOBALCHARARRAY", -// [JB] end of new pcodes - "PCD_SETACTORANGLE", - "PCD_GRABINPUT", - "PCD_SETMOUSEPOINTER", - "PCD_MOVEMOUSEPOINTER", - "PCD_SPAWNPROJECTILE", - "PCD_GETSECTORLIGHTLEVEL", - "PCD_GETACTORCEILINGZ", - "PCD_SETACTORPOSITION", - "PCD_CLEARACTORINVENTORY", - "PCD_GIVEACTORINVENTORY", - "PCD_TAKEACTORINVENTORY", - "PCD_CHECKACTORINVENTORY", - "PCD_THINGCOUNTNAME", - "PCD_SPAWNSPOTFACING", - "PCD_PLAYERCLASS", - //[MW] start my p-codes - "PCD_ANDSCRIPTVAR", - "PCD_ANDMAPVAR", - "PCD_ANDWORLDVAR", - "PCD_ANDGLOBALVAR", - "PCD_ANDMAPARRAY", - "PCD_ANDWORLDARRAY", - "PCD_ANDGLOBALARRAY", - "PCD_EORSCRIPTVAR", - "PCD_EORMAPVAR", - "PCD_EORWORLDVAR", - "PCD_EORGLOBALVAR", - "PCD_EORMAPARRAY", - "PCD_EORWORLDARRAY", - "PCD_EORGLOBALARRAY", - "PCD_ORSCRIPTVAR", - "PCD_ORMAPVAR", - "PCD_ORWORLDVAR", - "PCD_ORGLOBALVAR", - "PCD_ORMAPARRAY", - "PCD_ORWORLDARRAY", - "PCD_ORGLOBALARRAY", - "PCD_LSSCRIPTVAR", - "PCD_LSMAPVAR", - "PCD_LSWORLDVAR", - "PCD_LSGLOBALVAR", - "PCD_LSMAPARRAY", - "PCD_LSWORLDARRAY", - "PCD_LSGLOBALARRAY", - "PCD_RSSCRIPTVAR", - "PCD_RSMAPVAR", - "PCD_RSWORLDVAR", - "PCD_RSGLOBALVAR", - "PCD_RSMAPARRAY", - "PCD_RSWORLDARRAY", - "PCD_RSGLOBALARRAY", - //[MW] end my p-codes - "PCD_GETPLAYERINFO", - "PCD_CHANGELEVEL", - "PCD_SECTORDAMAGE", - "PCD_REPLACETEXTURES", - "PCD_NEGATEBINARY", - "PCD_GETACTORPITCH", - "PCD_SETACTORPITCH", - "PCD_PRINTBIND", - "PCD_SETACTORSTATE", - "PCD_THINGDAMAGE2", - "PCD_USEINVENTORY", - "PCD_USEACTORINVENTORY", - "PCD_CHECKACTORCEILINGTEXTURE", - "PCD_CHECKACTORFLOORTEXTURE", - "PCD_GETACTORLIGHTLEVEL", - "PCD_SETMUGSHOTSTATE", - "PCD_THINGCOUNTSECTOR", - "PCD_THINGCOUNTNAMESECTOR", - "PCD_CHECKPLAYERCAMERA", - "PCD_MORPHACTOR", - "PCD_UNMORPHACTOR", - "PCD_GETPLAYERINPUT", - "PCD_CLASSIFYACTOR", - "PCD_PRINTBINARY", - "PCD_PRINTHEX", - "PCD_CALLFUNC", - "PCD_SAVESTRING", // [FDARI] - "PCD_PRINTMAPCHRANGE", // [FDARI] output range - "PCD_PRINTWORLDCHRANGE", - "PCD_PRINTGLOBALCHRANGE", - "PCD_STRCPYTOMAPCHRANGE", // [FDARI] input range - "PCD_STRCPYTOWORLDCHRANGE", - "PCD_STRCPYTOGLOBALCHRANGE", - "PCD_PUSHFUNCTION", // from Eternity - "PCD_CALLSTACK", // from Eternity - "PCD_SCRIPTWAITNAMED", - "PCD_TRANSLATIONRANGE3", - "PCD_GOTOSTACK", - "PCD_ASSIGNSCRIPTARRAY", - "PCD_PUSHSCRIPTARRAY", - "PCD_ADDSCRIPTARRAY", - "PCD_SUBSCRIPTARRAY", - "PCD_MULSCRIPTARRAY", - "PCD_DIVSCRIPTARRAY", - "PCD_MODSCRIPTARRAY", - "PCD_INCSCRIPTARRAY", - "PCD_DECSCRIPTARRAY", - "PCD_ANDSCRIPTARRAY", - "PCD_EORSCRIPTARRAY", - "PCD_ORSCRIPTARRAY", - "PCD_LSSCRIPTARRAY", - "PCD_RSSCRIPTARRAY", - "PCD_PRINTSCRIPTCHARARRAY", - "PCD_PRINTSCRIPTCHRANGE", - "PCD_STRCPYTOSCRIPTCHRANGE", - "PCD_LSPEC5EX", - "PCD_LSPEC5EXRESULT", -}; - -// CODE -------------------------------------------------------------------- - -//========================================================================== -// -// PC_OpenObject -// -//========================================================================== - -void PC_OpenObject(char *name, size_t size, int flags) -{ - if(ObjectOpened == YES) - { - PC_CloseObject(); - } - if(strlen(name) >= MAX_FILE_NAME_LENGTH) - { - ERR_Exit(ERR_FILE_NAME_TOO_LONG, NO, name); - } - strcpy(ObjectName, name); - pc_Buffer = MS_Alloc(size, ERR_ALLOC_PCODE_BUFFER); - pc_BufferPtr = pc_Buffer; - pc_Address = 0; - ObjectFlags = flags; - BufferSize = size; - pc_ScriptCount = 0; - ObjectOpened = YES; - PC_AppendString("ACS"); - PC_SkipInt(); // Script table offset -} - -//========================================================================== -// -// PC_CloseObject -// -//========================================================================== - -void PC_CloseObject(void) -{ - MS_Message(MSG_DEBUG, "---- PC_CloseObject ----\n"); - while (pc_Address & 3) - { - PC_AppendByte (0); - } - if(!pc_NoShrink || (NumStringLists > 0) || - (pc_FunctionCount > 0) || MapVariablesInit || NumArrays != 0 || - pc_EncryptStrings || NumImports != 0 || HaveExtendedScripts || - HaveScriptArrays) - { - if(pc_EnforceHexen) - { - ERR_Exit(ERR_NOT_HEXEN, NO); - } - if(pc_WarnNotHexen) - { - fprintf(stderr, "\nThese scripts have been upgraded because they use new features.\n" - "They will not be compatible with Hexen.\n"); - } - CloseNew(); - } - else - { - CloseOld(); - } - if(MS_SaveFile(ObjectName, pc_Buffer, pc_Address) == FALSE) - { - ERR_Exit(ERR_SAVE_OBJECT_FAILED, NO); - } -} - -//========================================================================== -// -// CloseOld -// -//========================================================================== - -static void CloseOld(void) -{ - int i; - - STR_WriteStrings(); - PC_WriteInt((U_INT)pc_Address, 4); - PC_AppendInt((U_INT)pc_ScriptCount); - for(i = 0; i < pc_ScriptCount; ++i) - { - scriptInfo_t *info = &ScriptInfo[i]; - MS_Message(MSG_DEBUG, "Script %d, address = %d, arg count = %d\n", - info->number, info->address, info->argCount); - PC_AppendInt((U_INT)(info->number + info->type * 1000)); - PC_AppendInt((U_INT)info->address); - PC_AppendInt((U_INT)info->argCount); - } - STR_WriteList(); -} - -//========================================================================== -// -// CloseNew -// -// Creates a new-format ACS file. For programs that don't know any better, -// this will look just like an old ACS file with no scripts or strings but -// with some extra junk in the middle. Both WadAuthor and DeePsea will not -// accept ACS files that do not have the ACS\0 header. Worse, WadAuthor -// will hang if the file begins with ACS\0 but does not look like something -// that might have been created with Raven's ACC. Thus, the chunks live in -// the string block, and there are two 0 dwords at the end of the file. -// -//========================================================================== - -static void CloseNew(void) -{ - int i, j, count; - int chunkStart; - - if(pc_WadAuthor) - { - CreateDummyScripts(); - } - - chunkStart = pc_Address; - - // Only write out those scripts that this acs file actually provides. - for(i = j = 0; i < pc_ScriptCount; ++i) - { - if(!ScriptInfo[i].imported) - { - ++j; - } - } - if(j > 0) - { - PC_Append("SPTR", 4); - PC_AppendInt(j * 8); - for(i = 0; i < pc_ScriptCount; i++) - { - scriptInfo_t *info = &ScriptInfo[i]; - if(!info->imported) - { - MS_Message(MSG_DEBUG, "Script %d, address = %d, arg count = %d\n", - info->number, info->address, info->argCount); - PC_AppendWord(info->number); - PC_AppendByte(info->type); - PC_AppendByte(info->argCount); - PC_AppendInt((U_INT)info->address); - } - } - } - - // If any scripts have more than the maximum number of arguments, output them. - for(i = j = 0; i < pc_ScriptCount; ++i) - { - if(!ScriptInfo[i].imported && ScriptInfo[i].varCount > MAX_SCRIPT_VARIABLES) - { - ++j; - } - } - if(j > 0) - { - PC_Append("SVCT", 4); - PC_AppendInt(j * 4); - for(i = 0; i < pc_ScriptCount; ++i) - { - scriptInfo_t *info = &ScriptInfo[i]; - if(!info->imported && info->varCount > MAX_SCRIPT_VARIABLES) - { - MS_Message(MSG_DEBUG, "Script %d, var count = %d\n", - info->number, info->varCount); - PC_AppendWord(info->number); - PC_AppendWord(info->varCount); - } - } - } - - // Write script flags in a separate chunk, so older ZDooms don't get confused - for(i = j = 0; i < pc_ScriptCount; ++i) - { - if(!ScriptInfo[i].imported && ScriptInfo[i].flags != 0) - { - ++j; - } - } - if (j > 0) - { - PC_Append("SFLG", 4); - PC_AppendInt(j * 4); - for(i = 0; i < pc_ScriptCount; ++i) - { - scriptInfo_t *info = &ScriptInfo[i]; - if(!info->imported && info->flags != 0) - { - PC_AppendWord(info->number); - PC_AppendWord(info->flags); - } - } - } - - // Add chunks for scripts with arrays - for(i = 0; i < pc_ScriptCount; ++i) - { - if(ScriptInfo[i].arrayCount) - { - PC_Append("SARY", 4); - PC_AppendInt(2 + ScriptInfo[i].arrayCount * 4); - PC_AppendWord(ScriptInfo[i].number); - for(j = 0; j < ScriptInfo[i].arrayCount; ++j) - { - PC_AppendInt(ScriptInfo[i].arraySizes[j]); - } - } - } - - // Write the string table for named scripts. - STR_WriteListChunk(STRLIST_NAMEDSCRIPTS, MAKE4CC('S','N','A','M'), NO); - - // Write the functions provided by this file. - if(pc_FunctionCount > 0) - { - PC_Append("FUNC", 4); - PC_AppendInt(pc_FunctionCount * 8); - for(i = 0; i < pc_FunctionCount; ++i) - { - functionInfo_t *info = &FunctionInfo[i]; - MS_Message(MSG_DEBUG, "Function %d:%s, address = %d, arg count = %d, var count = %d\n", - i, STR_GetString(STRLIST_FUNCTIONS, info->name), - info->address, info->argCount, info->localCount); - PC_AppendByte(info->argCount); - PC_AppendByte(info->localCount); - PC_AppendByte((U_BYTE)(info->hasReturnValue?1:0)); - PC_AppendByte(0); - PC_AppendInt((U_INT)info->address); - } - STR_WriteListChunk(STRLIST_FUNCTIONS, MAKE4CC('F','N','A','M'), NO); - } - - // Add chunks for functions with arrays - for(i = 0; i < pc_FunctionCount; ++i) - { - if(FunctionInfo[i].arrayCount) - { - PC_Append("FARY", 4); - PC_AppendInt(2 + FunctionInfo[i].arrayCount * 4); - PC_AppendWord((U_WORD)i); - for(j = 0; j < FunctionInfo[i].arrayCount; ++j) - { - PC_AppendInt(FunctionInfo[i].arraySizes[j]); - } - } - } - - - if(STR_ListSize() > 0) - { - STR_WriteChunk(pc_EncryptStrings); - } - - STR_WriteListChunk(STRLIST_PICS, MAKE4CC('P','I','C','S'), NO); - if(MapVariablesInit) - { - int j; - - for(i = 0; i < pa_MapVarCount; ++i) - { - if(MapVariables[i].initializer != 0) - break; - } - for(j = pa_MapVarCount-1; j > i; --j) - { - if(MapVariables[j].initializer != 0) - break; - } - ++j; - - if (i < j) - { - PC_Append("MINI", 4); - PC_AppendInt((j-i)*4+4); - PC_AppendInt(i); // First map var defined - for(; i < j; ++i) - { - PC_AppendInt(MapVariables[i].initializer); - } - } - } - - // If this is a library, record which map variables are - // initialized with strings. - if(ImportMode == IMPORT_Exporting) - { - count = 0; - - for(i = 0; i < pa_MapVarCount; ++i) - { - if(MapVariables[i].isString) - { - ++count; - } - } - if(count > 0) - { - PC_Append("MSTR", 4); - PC_AppendInt(count*4); - for(i = 0; i < pa_MapVarCount; ++i) - { - if(MapVariables[i].isString) - { - PC_AppendInt(i); - } - } - } - - // Now do the same thing for arrays. - for(count = 0, i = 0; i < pa_MapVarCount; ++i) - { - if(ArrayOfStrings[i]) - { - ++count; - } - } - if(count > 0) - { - PC_Append("ASTR", 4); - PC_AppendInt(count*4); - for(i = 0; i < pa_MapVarCount; ++i) - { - if(ArrayOfStrings[i]) - { - PC_AppendInt(i); - } - } - } - } - - // Publicize the names of map variables in a library. - if(ImportMode == IMPORT_Exporting) - { - for(i = 0; i < pa_MapVarCount; ++i) - { - if(!MapVariables[i].imported) - { - STR_AppendToList(STRLIST_MAPVARS, MapVariables[i].name); - } - else - { - STR_AppendToList(STRLIST_MAPVARS, NULL); - } - } - STR_WriteListChunk(STRLIST_MAPVARS, MAKE4CC('M','E','X','P'), NO); - } - - // Record the names of imported map variables - count = 0; - for(i = 0; i < pa_MapVarCount; ++i) - { - if(MapVariables[i].imported && !ArraySizes[i]) - { - count += 5 + strlen(MapVariables[i].name); - } - } - if(count > 0) - { - PC_Append("MIMP", 4); - PC_AppendInt(count); - for(i = 0; i < pa_MapVarCount; ++i) - { - if(MapVariables[i].imported && !ArraySizes[i]) - { - PC_AppendInt(i); - PC_AppendString(MapVariables[i].name); - } - } - } - - if(NumArrays) - { - int count; - - // Arrays defined here - for(count = 0, i = 0; i < pa_MapVarCount; ++i) - { - if(ArraySizes[i] && !MapVariables[i].imported) - { - ++count; - } - } - if(count) - { - PC_Append("ARAY", 4); - PC_AppendInt(count*8); - for(i = 0; i < pa_MapVarCount; ++i) - { - if(ArraySizes[i] && !MapVariables[i].imported) - { - PC_AppendInt(i); - PC_AppendInt(ArraySizes[i]); - } - } - for(i = 0; i < pa_MapVarCount; ++i) - { - if(ArrayInits[i]) - { - int j; - - PC_Append("AINI", 4); - PC_AppendInt(ArraySizes[i]*4+4); - PC_AppendInt((U_INT)i); - MS_Message(MSG_DEBUG, "Writing array initializers for array %d (size %d)\n", i, ArraySizes[i]); - for(j = 0; j < ArraySizes[i]; ++j) - { - PC_AppendInt((U_INT)ArrayInits[i][j]); - } - } - } - } - - // Arrays imported from elsewhere - for(count = 0, j = i = 0; i < pa_MapVarCount; ++i) - { - if(ArraySizes[i] && MapVariables[i].imported) - { - count += 9 + strlen(MapVariables[i].name); - ++j; - } - } - if(count) - { - PC_Append("AIMP", 4); - PC_AppendInt(count+4); - PC_AppendInt(j); - for(i = 0; i < pa_MapVarCount; ++i) - { - if(ArraySizes[i] && MapVariables[i].imported) - { - PC_AppendInt(i); - PC_AppendInt(ArraySizes[i]); - PC_AppendString(MapVariables[i].name); - } - } - } - } - - // Add a dummy chunk to indicate if this object is a library. - if(ImportMode == IMPORT_Exporting) - { - PC_Append("ALIB", 4); - PC_AppendInt(0); - } - - // Record libraries imported by this object. - if(NumImports > 0) - { - count = 0; - for(i = 0; i < NumImports; ++i) - { - count += strlen(Imports[i]) + 1; - } - if(count > 0) - { - PC_Append("LOAD", 4); - PC_AppendInt(count); - for(i = 0; i < NumImports; ++i) - { - PC_AppendString(Imports[i]); - } - } - } - - PC_AppendInt((U_INT)chunkStart); - if(pc_NoShrink) - { - PC_Append("ACSE", 4); - } - else - { - PC_Append("ACSe", 4); - } - PC_WriteInt((U_INT)pc_Address, 4); - - // WadAuthor compatibility when creating a library is pointless, because - // that editor does not know anything about libraries and will never - // find their scripts ever. - if(pc_WadAuthor && ImportMode != IMPORT_Exporting) - { - RecordDummyScripts(); - } - else - { - PC_AppendInt(0); - } - PC_AppendInt(0); -} - -//========================================================================== -// -// CreateDummyScripts -// -//========================================================================== - -static void CreateDummyScripts(void) -{ - int i; - - MS_Message(MSG_DEBUG, "Creating dummy scripts to make WadAuthor happy.\n"); - if(pc_Address%4 != 0) - { // Need to align - U_INT pad = 0; - PC_Append((void *)&pad, 4-(pc_Address%4)); - } - pc_DummyAddress = pc_Address; - for(i = 0; i < pc_ScriptCount; ++i) - { - // Only create dummies for scripts WadAuthor could care about. - if(!ScriptInfo[i].imported && ScriptInfo[i].number >= 0 && ScriptInfo[i].number <= 255) - { - PC_AppendCmd(PCD_TERMINATE); - if(!pc_NoShrink) - { - PC_AppendCmd(PCD_NOP); - PC_AppendCmd(PCD_NOP); - PC_AppendCmd(PCD_NOP); - } - } - } -} - -//========================================================================== -// -// RecordDummyScripts -// -//========================================================================== - -static void RecordDummyScripts(void) -{ - int i, j, count; - - for(i = count = 0; i < pc_ScriptCount; ++i) - { - if(!ScriptInfo[i].imported && ScriptInfo[i].number >= 0 && ScriptInfo[i].number <= 255) - { - ++count; - } - } - PC_AppendInt((U_INT)count); - for(i = j = 0; i < pc_ScriptCount; ++i) - { - scriptInfo_t *info = &ScriptInfo[i]; - if(!info->imported && info->number >= 0 && ScriptInfo[i].number <= 255) - { - MS_Message(MSG_DEBUG, "Dummy script %d, address = %d, arg count = %d\n", - info->number, info->address, info->argCount); - PC_AppendInt((U_INT)info->number); - PC_AppendInt((U_INT)pc_DummyAddress + j*4); - PC_AppendInt((U_INT)info->argCount); - j++; - } - } -} - -//========================================================================== -// -// GrowBuffer -// -//========================================================================== - -void GrowBuffer(void) -{ - ptrdiff_t buffpos = pc_BufferPtr - pc_Buffer; - - BufferSize *= 2; - pc_Buffer = MS_Realloc(pc_Buffer, BufferSize, ERR_PCODE_BUFFER_OVERFLOW); - pc_BufferPtr = pc_Buffer + buffpos; -} - -//========================================================================== -// -// PC_Append functions -// -//========================================================================== - -static void Append(void *buffer, size_t size) -{ - if (ImportMode != IMPORT_Importing) - { - if(pc_Address+size > BufferSize) - { - GrowBuffer (); - } - memcpy(pc_BufferPtr, buffer, size); - pc_BufferPtr += size; - pc_Address += size; - } -} - -void PC_Append(void *buffer, size_t size) -{ - if (ImportMode != IMPORT_Importing) - { - MS_Message(MSG_DEBUG, "AD> %06d = (%d bytes)\n", pc_Address, size); - Append(buffer, size); - } -} - -void PC_AppendByte(U_BYTE val) -{ - if (ImportMode != IMPORT_Importing) - { - MS_Message(MSG_DEBUG, "AB> %06d = %d\n", pc_Address, val); - Append(&val, sizeof(U_BYTE)); - } -} - -void PC_AppendWord(U_WORD val) -{ - if (ImportMode != IMPORT_Importing) - { - MS_Message(MSG_DEBUG, "AW> %06d = %d\n", pc_Address, val); - val = MS_LittleUWORD(val); - Append(&val, sizeof(U_WORD)); - } -} - -void PC_AppendInt(U_INT val) -{ - if (ImportMode != IMPORT_Importing) - { - MS_Message(MSG_DEBUG, "AL> %06d = %d\n", pc_Address, val); - val = MS_LittleUINT(val); - Append(&val, sizeof(U_INT)); - } -} - -void PC_AppendString(char *string) -{ - if (ImportMode != IMPORT_Importing) - { - int length; - - length = strlen(string)+1; - MS_Message(MSG_DEBUG, "AS> %06d = \"%s\" (%d bytes)\n", - pc_Address, string, length); - Append(string, length); - } -} - -void PC_AppendCmd(pcd_t command) -{ - boolean dupbyte = NO; - if (ImportMode != IMPORT_Importing) - { - pc_LastAppendedCommand = command; - if (pc_NoShrink) - { - MS_Message(MSG_DEBUG, "AC> %06d = #%d:%s\n", pc_Address, - command, PCDNames[command]); - command = MS_LittleUINT(command); - Append(&command, sizeof(U_INT)); - } - else - { - U_BYTE cmd; - if (command == PCD_DUP && PushByteAddr) - { // If the last instruction was PCD_PUSHBYTE, convert this PCD_DUP to a - // duplicate PCD_PUSHBYTE, so it can be merged into a single instruction below. - command = PCD_PUSHBYTE; - dupbyte = YES; - MS_Message(MSG_DEBUG, "AC> PCD_DUP changed to PCD_PUSHBYTE\n"); - } - else if (command != PCD_PUSHBYTE && PushByteAddr) - { // Maybe shrink a PCD_PUSHBYTE sequence into PCD_PUSHBYTES - int runlen = (pc_Address - PushByteAddr) / 2; - int i; - - if (runlen > 5) - { - pc_Buffer[PushByteAddr] = PCD_PUSHBYTES; - for (i = 0; i < runlen; i++) - { - pc_Buffer[PushByteAddr+i+2] = pc_Buffer[PushByteAddr+i*2+1]; - } - pc_Buffer[PushByteAddr+1] = runlen; - pc_Address = PushByteAddr + runlen + 2; - pc_BufferPtr = pc_Buffer + pc_Address; - MS_Message(MSG_DEBUG, "AC> Last %d PCD_PUSHBYTEs changed to #%d:PCD_PUSHBYTES\n", - runlen, PCD_PUSHBYTES); - } - else if (runlen > 1) - { - pc_Buffer[PushByteAddr] = PCD_PUSH2BYTES + runlen - 2; - for (i = 1; i < runlen; i++) - { - pc_Buffer[PushByteAddr+1+i] = pc_Buffer[PushByteAddr+1+i*2]; - } - pc_Address = PushByteAddr + runlen + 1; - pc_BufferPtr = pc_Buffer + pc_Address; - MS_Message(MSG_DEBUG, "AC> Last %d PCD_PUSHBYTEs changed to #%d:PCD_PUSH%dBYTES\n", - runlen, PCD_PUSH2BYTES+runlen-2, runlen); - } - PushByteAddr = 0; - } - else if(command == PCD_PUSHBYTE && PushByteAddr == 0) - { // Remember the first PCD_PUSHBYTE, in case there are more - PushByteAddr = pc_Address; - } - MS_Message(MSG_DEBUG, "AC> %06d = #%d:%s\n", pc_Address, - command, PCDNames[command]); - - if (command < 256-16) - { - cmd = command; - Append(&cmd, sizeof(U_BYTE)); - } - else - { - // Room for expansion: The top 16 pcodes in the [0,255] - // range select a set of pcodes, and the next byte is - // the pcode in that set. - cmd = ((command - (256-16)) >> 8) + (256-16); - Append(&cmd, sizeof(U_BYTE)); - cmd = (command - (256-16)) & 255; - Append(&cmd, sizeof(U_BYTE)); - } - if (dupbyte) - { - PC_AppendByte(pc_Buffer[pc_Address-2]); - } - } - } -} - -//========================================================================== -// -// PC_AppendShrink -// -//========================================================================== - -void PC_AppendShrink(U_BYTE val) -{ - if(pc_NoShrink) - { - PC_AppendInt(val); - } - else - { - PC_AppendByte(val); - } -} - -//========================================================================== -// -// PC_AppendPushVal -// -//========================================================================== - -void PC_AppendPushVal(U_INT val) -{ - if(pc_NoShrink || val > 255) - { - PC_AppendCmd(PCD_PUSHNUMBER); - PC_AppendInt(val); - } - else - { - PC_AppendCmd(PCD_PUSHBYTE); - PC_AppendByte((U_BYTE)val); - } -} - -//========================================================================== -// -// PC_Write functions -// -//========================================================================== - -static void Write(void *buffer, size_t size, int address) -{ - if (ImportMode != IMPORT_Importing) - { - if(address+size > BufferSize) - { - GrowBuffer(); - } - memcpy(pc_Buffer+address, buffer, size); - } -} - -void PC_Write(void *buffer, size_t size, int address) -{ - if (ImportMode != IMPORT_Importing) - { - MS_Message(MSG_DEBUG, "WD> %06d = (%d bytes)\n", address, size); - Write(buffer, size, address); - } -} - -void PC_WriteByte(U_BYTE val, int address) -{ - if (ImportMode != IMPORT_Importing) - { - MS_Message(MSG_DEBUG, "WB> %06d = %d\n", address, val); - Write(&val, sizeof(U_BYTE), address); - } -} - -/* -void PC_WriteWord(U_WORD val, int address) -{ - MS_Message(MSG_DEBUG, "WW> %06d = %d\n", address, val); - val = MS_LittleUWORD(val); - Write(&val, sizeof(U_WORD), address); -} -*/ - -void PC_WriteInt(U_INT val, int address) -{ - if (ImportMode != IMPORT_Importing) - { - MS_Message(MSG_DEBUG, "WL> %06d = %d\n", address, val); - val = MS_LittleUINT(val); - Write(&val, sizeof(U_INT), address); - } - pc_LastAppendedCommand = PCD_NOP; -} - -void PC_WriteString(char *string, int address) -{ - if (ImportMode != IMPORT_Importing) - { - int length; - - length = strlen(string)+1; - MS_Message(MSG_DEBUG, "WS> %06d = \"%s\" (%d bytes)\n", - address, string, length); - Write(string, length, address); - } -} - -void PC_WriteCmd(pcd_t command, int address) -{ - if (ImportMode != IMPORT_Importing) - { - MS_Message(MSG_DEBUG, "WC> %06d = #%d:%s\n", address, - command, PCDNames[command]); - command = MS_LittleUINT(command); - Write(&command, sizeof(U_INT), address); - } -} - -//========================================================================== -// -// PC_Skip functions -// -//========================================================================== - -static void Skip(size_t size) -{ - if (ImportMode != IMPORT_Importing) - { - if(pc_Address+size > BufferSize) - { - GrowBuffer(); - } - pc_BufferPtr += size; - pc_Address += size; - } -} - -void PC_Skip(size_t size) -{ - if (ImportMode != IMPORT_Importing) - { - MS_Message(MSG_DEBUG, "SD> %06d (skip %d bytes)\n", pc_Address, size); - Skip(size); - } -} - -/* -void PC_SkipByte(void) -{ - MS_Message(MSG_DEBUG, "SB> %06d (skip byte)\n", pc_Address); - Skip(sizeof(U_BYTE)); -} -*/ - -/* -void PC_SkipWord(void) -{ - MS_Message(MSG_DEBUG, "SW> %06d (skip word)\n", pc_Address); - Skip(sizeof(U_WORD)); -} -*/ - -void PC_SkipInt(void) -{ - if (ImportMode != IMPORT_Importing) - { - MS_Message(MSG_DEBUG, "SL> %06d (skip int)\n", pc_Address); - Skip(sizeof(U_INT)); - } -} - -//========================================================================== -// -// PC_PutMapVariable -// -//========================================================================== - -void PC_PutMapVariable(int index, int value) -{ - if(index < MAX_MAP_VARIABLES) - { - MapVariables[index].isString = pa_ConstExprIsString; - MapVariables[index].initializer = value; - MapVariablesInit = YES; - if(pc_EnforceHexen) - { - ERR_Error(ERR_HEXEN_COMPAT, YES); - } - } -} - -//========================================================================== -// -// PC_NameMapVariable -// -//========================================================================== - -void PC_NameMapVariable(int index, symbolNode_t *sym) -{ - if(index < MAX_MAP_VARIABLES) - { - MapVariables[index].name = sym->name; - MapVariables[index].imported = sym->imported; - } -} - -//========================================================================== -// -// PC_AddScript -// -//========================================================================== - -void PC_AddScript(int number, int type, int flags, int argCount) -{ - scriptInfo_t *script; - int i; - - if (flags != 0 || number < 0 || number >= 1000) - { - HaveExtendedScripts = YES; - if(pc_EnforceHexen) - { - ERR_Error(ERR_HEXEN_COMPAT, YES); - } - } - - for (i = 0; i < pc_ScriptCount; i++) - { - if (ScriptInfo[i].number == number) - { - ERR_Error(ERR_SCRIPT_ALREADY_DEFINED, YES); - } - } - if(pc_ScriptCount == MAX_SCRIPT_COUNT) - { - ERR_Error(ERR_TOO_MANY_SCRIPTS, YES); - } - else - { - script = &ScriptInfo[pc_ScriptCount]; - script->number = number; - script->type = type; - script->address = (ImportMode == IMPORT_Importing) ? 0 : pc_Address; - script->argCount = argCount; - script->flags = flags; - script->srcLine = tk_Line; - script->imported = (ImportMode == IMPORT_Importing) ? YES : NO; - script->arrayCount = 0; - pc_ScriptCount++; - } -} - -//========================================================================== -// -// PC_SetScriptVarCount -// -// Sets the number of local variables used by a script, including -// arguments. -// -//========================================================================== - -void PC_SetScriptVarCount(int number, int type, int varCount, int arrayCount, int *arraySizes) -{ - int i; - - for(i = 0; i < pc_ScriptCount; i++) - { - if(ScriptInfo[i].number == number && ScriptInfo[i].type == type) - { - ScriptInfo[i].varCount = varCount; - if (arrayCount > 0 && arrayCount < MAX_SCRIPT_ARRAYS) - { - ScriptInfo[i].arrayCount = (U_BYTE)arrayCount; - memcpy(ScriptInfo[i].arraySizes, arraySizes, arrayCount * sizeof(int)); - HaveScriptArrays = YES; - } - break; - } - } -} - -//========================================================================== -// -// PC_AddFunction -// -//========================================================================== - -void PC_AddFunction(symbolNode_t *sym, int arrayCount, int *arraySizes) -{ - functionInfo_t *function; - int maxFunctionCount = pc_NoShrink ? MAX_FUNCTION_COUNT : (1 << CHAR_BIT * sizeof(U_BYTE)); - - if(pc_FunctionCount == maxFunctionCount) - { - ERR_Error(ERR_TOO_MANY_FUNCTIONS, YES, NULL); - } - function = &FunctionInfo[pc_FunctionCount]; - function->hasReturnValue = (U_BYTE)sym->info.scriptFunc.hasReturnValue; - function->argCount = (U_BYTE)sym->info.scriptFunc.argCount; - function->localCount = (U_BYTE)sym->info.scriptFunc.varCount; - function->name = STR_AppendToList (STRLIST_FUNCTIONS, sym->name); - function->address = sym->info.scriptFunc.address; - sym->info.scriptFunc.funcNumber = pc_FunctionCount; - if (arrayCount > 0 && arrayCount < MAX_SCRIPT_ARRAYS) - { - function->arrayCount = (U_BYTE)arrayCount; - memcpy(function->arraySizes, arraySizes, arrayCount * sizeof(int)); - HaveScriptArrays = YES; - } - else - { - function->arrayCount = 0; - } - pc_FunctionCount++; -} - -//========================================================================== -// -// PC_AddArray -// -//========================================================================== - -void PC_AddArray(int index, int size) -{ - NumArrays++; - ArraySizes[index] = size; - if(pc_EnforceHexen) - { - ERR_Error(ERR_HEXEN_COMPAT, YES); - } -} - -//========================================================================== -// -// PC_InitArray -// -//========================================================================== - -void PC_InitArray(int index, int *entries, boolean hasStrings) -{ - int i; - - // If the array is just initialized to zeros, then we don't need to - // remember the initializer. - for(i = 0; i < ArraySizes[index]; ++i) - { - if(entries[i] != 0) - { - break; - } - } - if(i < ArraySizes[index]) - { - ArrayInits[index] = MS_Alloc(ArraySizes[index]*sizeof(int), ERR_OUT_OF_MEMORY); - memcpy(ArrayInits[index], entries, ArraySizes[index]*sizeof(int)); - } - ArrayOfStrings[index] = hasStrings; -} - -//========================================================================== -// -// PC_AddImport -// -//========================================================================== - -int PC_AddImport(char *name) -{ - if (NumImports >= MAX_IMPORTS) - { - ERR_Exit(ERR_TOO_MANY_IMPORTS, YES); - } - else if(pc_EnforceHexen) - { - ERR_Error(ERR_HEXEN_COMPAT, YES); - } - strncpy(Imports[NumImports], name, 8); - return NumImports++; -} + +//************************************************************************** +//** +//** pcode.c +//** +//************************************************************************** + +// HEADER FILES ------------------------------------------------------------ + +#include +#include +#include +#include +#include "pcode.h" +#include "common.h" +#include "error.h" +#include "misc.h" +#include "strlist.h" +#include "token.h" +#include "symbol.h" +#include "parse.h" + +// MACROS ------------------------------------------------------------------ + +// TYPES ------------------------------------------------------------------- + +typedef struct scriptInfo_s +{ + S_WORD number; + U_BYTE type; + U_BYTE argCount; + U_BYTE arrayCount; + U_WORD varCount; + U_WORD flags; + int address; + int srcLine; + boolean imported; + int arraySizes[MAX_SCRIPT_ARRAYS]; +} scriptInfo_t; + +typedef struct functionInfo_s +{ + U_BYTE hasReturnValue; + U_BYTE argCount; + U_BYTE localCount; + U_BYTE arrayCount; + int address; + int name; + int arraySizes[MAX_SCRIPT_ARRAYS]; +} functionInfo_t; + +typedef struct mapVarInfo_s +{ + int initializer; + boolean isString; + char *name; + boolean imported; +} mapVarInfo_t; + +// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- + +// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- + +// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- + +static void GrowBuffer(void); +static void Append(void *buffer, size_t size); +static void Write(void *buffer, size_t size, int address); +static void Skip(size_t size); +static void CloseOld(void); +static void CloseNew(void); +static void CreateDummyScripts(void); +static void RecordDummyScripts(void); + +// EXTERNAL DATA DECLARATIONS ---------------------------------------------- + +// PUBLIC DATA DEFINITIONS ------------------------------------------------- + +int pc_Address; +byte *pc_Buffer; +byte *pc_BufferPtr; +int pc_ScriptCount; +int pc_FunctionCount; +boolean pc_NoShrink; +boolean pc_HexenCase; +boolean pc_EnforceHexen; +boolean pc_WarnNotHexen; +boolean pc_WadAuthor = TRUE; +boolean pc_EncryptStrings; +int pc_LastAppendedCommand; +int pc_DummyAddress; + +// PRIVATE DATA DEFINITIONS ------------------------------------------------ + +static size_t BufferSize; +static boolean ObjectOpened = NO; +static scriptInfo_t ScriptInfo[MAX_SCRIPT_COUNT]; +static functionInfo_t FunctionInfo[MAX_FUNCTION_COUNT]; +static int ArraySizes[MAX_MAP_VARIABLES]; +static int *ArrayInits[MAX_MAP_VARIABLES]; +static boolean ArrayOfStrings[MAX_MAP_VARIABLES]; +static int NumArrays; +static mapVarInfo_t MapVariables[MAX_MAP_VARIABLES]; +static boolean MapVariablesInit = NO; +static char ObjectName[MAX_FILE_NAME_LENGTH]; +static int ObjectFlags; +static int PushByteAddr; +static char Imports[MAX_IMPORTS][9]; +static int NumImports; +static boolean HaveExtendedScripts; +static boolean HaveScriptArrays; + +static char *PCDNames[PCODE_COMMAND_COUNT] = +{ + "PCD_NOP", + "PCD_TERMINATE", + "PCD_SUSPEND", + "PCD_PUSHNUMBER", + "PCD_LSPEC1", + "PCD_LSPEC2", + "PCD_LSPEC3", + "PCD_LSPEC4", + "PCD_LSPEC5", + "PCD_LSPEC1DIRECT", + "PCD_LSPEC2DIRECT", + "PCD_LSPEC3DIRECT", + "PCD_LSPEC4DIRECT", + "PCD_LSPEC5DIRECT", + "PCD_ADD", + "PCD_SUBTRACT", + "PCD_MULTIPLY", + "PCD_DIVIDE", + "PCD_MODULUS", + "PCD_EQ", + "PCD_NE", + "PCD_LT", + "PCD_GT", + "PCD_LE", + "PCD_GE", + "PCD_ASSIGNSCRIPTVAR", + "PCD_ASSIGNMAPVAR", + "PCD_ASSIGNWORLDVAR", + "PCD_PUSHSCRIPTVAR", + "PCD_PUSHMAPVAR", + "PCD_PUSHWORLDVAR", + "PCD_ADDSCRIPTVAR", + "PCD_ADDMAPVAR", + "PCD_ADDWORLDVAR", + "PCD_SUBSCRIPTVAR", + "PCD_SUBMAPVAR", + "PCD_SUBWORLDVAR", + "PCD_MULSCRIPTVAR", + "PCD_MULMAPVAR", + "PCD_MULWORLDVAR", + "PCD_DIVSCRIPTVAR", + "PCD_DIVMAPVAR", + "PCD_DIVWORLDVAR", + "PCD_MODSCRIPTVAR", + "PCD_MODMAPVAR", + "PCD_MODWORLDVAR", + "PCD_INCSCRIPTVAR", + "PCD_INCMAPVAR", + "PCD_INCWORLDVAR", + "PCD_DECSCRIPTVAR", + "PCD_DECMAPVAR", + "PCD_DECWORLDVAR", + "PCD_GOTO", + "PCD_IFGOTO", + "PCD_DROP", + "PCD_DELAY", + "PCD_DELAYDIRECT", + "PCD_RANDOM", + "PCD_RANDOMDIRECT", + "PCD_THINGCOUNT", + "PCD_THINGCOUNTDIRECT", + "PCD_TAGWAIT", + "PCD_TAGWAITDIRECT", + "PCD_POLYWAIT", + "PCD_POLYWAITDIRECT", + "PCD_CHANGEFLOOR", + "PCD_CHANGEFLOORDIRECT", + "PCD_CHANGECEILING", + "PCD_CHANGECEILINGDIRECT", + "PCD_RESTART", + "PCD_ANDLOGICAL", + "PCD_ORLOGICAL", + "PCD_ANDBITWISE", + "PCD_ORBITWISE", + "PCD_EORBITWISE", + "PCD_NEGATELOGICAL", + "PCD_LSHIFT", + "PCD_RSHIFT", + "PCD_UNARYMINUS", + "PCD_IFNOTGOTO", + "PCD_LINESIDE", + "PCD_SCRIPTWAIT", + "PCD_SCRIPTWAITDIRECT", + "PCD_CLEARLINESPECIAL", + "PCD_CASEGOTO", + "PCD_BEGINPRINT", + "PCD_ENDPRINT", + "PCD_PRINTSTRING", + "PCD_PRINTNUMBER", + "PCD_PRINTCHARACTER", + "PCD_PLAYERCOUNT", + "PCD_GAMETYPE", + "PCD_GAMESKILL", + "PCD_TIMER", + "PCD_SECTORSOUND", + "PCD_AMBIENTSOUND", + "PCD_SOUNDSEQUENCE", + "PCD_SETLINETEXTURE", + "PCD_SETLINEBLOCKING", + "PCD_SETLINESPECIAL", + "PCD_THINGSOUND", + "PCD_ENDPRINTBOLD", +// [RH] End of Hexen p-codes + "PCD_ACTIVATORSOUND", + "PCD_LOCALAMBIENTSOUND", + "PCD_SETLINEMONSTERBLOCKING", +// [BC] Start of new pcodes + "PCD_PLAYERBLUESKULL", + "PCD_PLAYERREDSKULL", + "PCD_PLAYERYELLOWSKULL", + "PCD_PLAYERMASTERSKULL", + "PCD_PLAYERBLUECARD", + "PCD_PLAYERREDCARD", + "PCD_PLAYERYELLOWCARD", + "PCD_PLAYERMASTERCARD", + "PCD_PLAYERBLACKSKULL", + "PCD_PLAYERSILVERSKULL", + "PCD_PLAYERGOLDSKULL", + "PCD_PLAYERBLACKCARD", + "PCD_PLAYERSILVERCARD", + "PCD_ISNETWORKGAME", + "PCD_PLAYERTEAM", + "PCD_PLAYERHEALTH", + "PCD_PLAYERARMORPOINTS", + "PCD_PLAYERFRAGS", + "PCD_PLAYEREXPERT", + "PCD_BLUETEAMCOUNT", + "PCD_REDTEAMCOUNT", + "PCD_BLUETEAMSCORE", + "PCD_REDTEAMSCORE", + "PCD_ISONEFLAGCTF", + "PCD_LSPEC6", + "PCD_LSPEC6DIRECT", + "PCD_PRINTNAME", + "PCD_MUSICCHANGE", + "PCD_CONSOLECOMMANDDIRECT", + "PCD_CONSOLECOMMAND", + "PCD_SINGLEPLAYER", +// [RH] End of Skull Tag p-codes + "PCD_FIXEDMUL", + "PCD_FIXEDDIV", + "PCD_SETGRAVITY", + "PCD_SETGRAVITYDIRECT", + "PCD_SETAIRCONTROL", + "PCD_SETAIRCONTROLDIRECT", + "PCD_CLEARINVENTORY", + "PCD_GIVEINVENTORY", + "PCD_GIVEINVENTORYDIRECT", + "PCD_TAKEINVENTORY", + "PCD_TAKEINVENTORYDIRECT", + "PCD_CHECKINVENTORY", + "PCD_CHECKINVENTORYDIRECT", + "PCD_SPAWN", + "PCD_SPAWNDIRECT", + "PCD_SPAWNSPOT", + "PCD_SPAWNSPOTDIRECT", + "PCD_SETMUSIC", + "PCD_SETMUSICDIRECT", + "PCD_LOCALSETMUSIC", + "PCD_LOCALSETMUSICDIRECT", + "PCD_PRINTFIXED", + "PCD_PRINTLOCALIZED", + "PCD_MOREHUDMESSAGE", + "PCD_OPTHUDMESSAGE", + "PCD_ENDHUDMESSAGE", + "PCD_ENDHUDMESSAGEBOLD", + "PCD_SETSTYLE", + "PCD_SETSTYLEDIRECT", + "PCD_SETFONT", + "PCD_SETFONTDIRECT", + "PCD_PUSHBYTE", + "PCD_LSPEC1DIRECTB", + "PCD_LSPEC2DIRECTB", + "PCD_LSPEC3DIRECTB", + "PCD_LSPEC4DIRECTB", + "PCD_LSPEC5DIRECTB", + "PCD_DELAYDIRECTB", + "PCD_RANDOMDIRECTB", + "PCD_PUSHBYTES", + "PCD_PUSH2BYTES", + "PCD_PUSH3BYTES", + "PCD_PUSH4BYTES", + "PCD_PUSH5BYTES", + "PCD_SETTHINGSPECIAL", + "PCD_ASSIGNGLOBALVAR", + "PCD_PUSHGLOBALVAR", + "PCD_ADDGLOBALVAR", + "PCD_SUBGLOBALVAR", + "PCD_MULGLOBALVAR", + "PCD_DIVGLOBALVAR", + "PCD_MODGLOBALVAR", + "PCD_INCGLOBALVAR", + "PCD_DECGLOBALVAR", + "PCD_FADETO", + "PCD_FADERANGE", + "PCD_CANCELFADE", + "PCD_PLAYMOVIE", + "PCD_SETFLOORTRIGGER", + "PCD_SETCEILINGTRIGGER", + "PCD_GETACTORX", + "PCD_GETACTORY", + "PCD_GETACTORZ", + "PCD_STARTTRANSLATION", + "PCD_TRANSLATIONRANGE1", + "PCD_TRANSLATIONRANGE2", + "PCD_ENDTRANSLATION", + "PCD_CALL", + "PCD_CALLDISCARD", + "PCD_RETURNVOID", + "PCD_RETURNVAL", + "PCD_PUSHMAPARRAY", + "PCD_ASSIGNMAPARRAY", + "PCD_ADDMAPARRAY", + "PCD_SUBMAPARRAY", + "PCD_MULMAPARRAY", + "PCD_DIVMAPARRAY", + "PCD_MODMAPARRAY", + "PCD_INCMAPARRAY", + "PCD_DECMAPARRAY", + "PCD_DUP", + "PCD_SWAP", + "PCD_WRITETOINI", + "PCD_GETFROMINI", + "PCD_SIN", + "PCD_COS", + "PCD_VECTORANGLE", + "PCD_CHECKWEAPON", + "PCD_SETWEAPON", + "PCD_TAGSTRING", + "PCD_PUSHWORLDARRAY", + "PCD_ASSIGNWORLDARRAY", + "PCD_ADDWORLDARRAY", + "PCD_SUBWORLDARRAY", + "PCD_MULWORLDARRAY", + "PCD_DIVWORLDARRAY", + "PCD_MODWORLDARRAY", + "PCD_INCWORLDARRAY", + "PCD_DECWORLDARRAY", + "PCD_PUSHGLOBALARRAY", + "PCD_ASSIGNGLOBALARRAY", + "PCD_ADDGLOBALARRAY", + "PCD_SUBGLOBALARRAY", + "PCD_MULGLOBALARRAY", + "PCD_DIVGLOBALARRAY", + "PCD_MODGLOBALARRAY", + "PCD_INCGLOBALARRAY", + "PCD_DECGLOBALARRAY", + "PCD_SETMARINEWEAPON", + "PCD_SETACTORPROPERTY", + "PCD_GETACTORPROPERTY", + "PCD_PLAYERNUMBER", + "PCD_ACTIVATORTID", + "PCD_SETMARINESPRITE", + "PCD_GETSCREENWIDTH", + "PCD_GETSCREENHEIGHT", + "PCD_THING_PROJECTILE2", + "PCD_STRLEN", + "PCD_SETHUDSIZE", + "PCD_GETCVAR", + "PCD_CASEGOTOSORTED", + "PCD_SETRESULTVALUE", + "PCD_GETLINEROWOFFSET", + "PCD_GETACTORFLOORZ", + "PCD_GETACTORANGLE", + "PCD_GETSECTORFLOORZ", + "PCD_GETSECTORCEILINGZ", + "PCD_LSPEC5RESULT", + "PCD_GETSIGILPIECES", + "PCD_GELEVELINFO", + "PCD_CHANGESKY", + "PCD_PLAYERINGAME", + "PCD_PLAYERISBOT", + "PCD_SETCAMERATOTEXTURE", + "PCD_ENDLOG", + "PCD_GETAMMOCAPACITY", + "PCD_SETAMMOCAPACITY", +// [JB] start of new pcodes + "PCD_PRINTMAPCHARARRAY", + "PCD_PRINTWORLDCHARARRAY", + "PCD_PRINTGLOBALCHARARRAY", +// [JB] end of new pcodes + "PCD_SETACTORANGLE", + "PCD_GRABINPUT", + "PCD_SETMOUSEPOINTER", + "PCD_MOVEMOUSEPOINTER", + "PCD_SPAWNPROJECTILE", + "PCD_GETSECTORLIGHTLEVEL", + "PCD_GETACTORCEILINGZ", + "PCD_SETACTORPOSITION", + "PCD_CLEARACTORINVENTORY", + "PCD_GIVEACTORINVENTORY", + "PCD_TAKEACTORINVENTORY", + "PCD_CHECKACTORINVENTORY", + "PCD_THINGCOUNTNAME", + "PCD_SPAWNSPOTFACING", + "PCD_PLAYERCLASS", + //[MW] start my p-codes + "PCD_ANDSCRIPTVAR", + "PCD_ANDMAPVAR", + "PCD_ANDWORLDVAR", + "PCD_ANDGLOBALVAR", + "PCD_ANDMAPARRAY", + "PCD_ANDWORLDARRAY", + "PCD_ANDGLOBALARRAY", + "PCD_EORSCRIPTVAR", + "PCD_EORMAPVAR", + "PCD_EORWORLDVAR", + "PCD_EORGLOBALVAR", + "PCD_EORMAPARRAY", + "PCD_EORWORLDARRAY", + "PCD_EORGLOBALARRAY", + "PCD_ORSCRIPTVAR", + "PCD_ORMAPVAR", + "PCD_ORWORLDVAR", + "PCD_ORGLOBALVAR", + "PCD_ORMAPARRAY", + "PCD_ORWORLDARRAY", + "PCD_ORGLOBALARRAY", + "PCD_LSSCRIPTVAR", + "PCD_LSMAPVAR", + "PCD_LSWORLDVAR", + "PCD_LSGLOBALVAR", + "PCD_LSMAPARRAY", + "PCD_LSWORLDARRAY", + "PCD_LSGLOBALARRAY", + "PCD_RSSCRIPTVAR", + "PCD_RSMAPVAR", + "PCD_RSWORLDVAR", + "PCD_RSGLOBALVAR", + "PCD_RSMAPARRAY", + "PCD_RSWORLDARRAY", + "PCD_RSGLOBALARRAY", + //[MW] end my p-codes + "PCD_GETPLAYERINFO", + "PCD_CHANGELEVEL", + "PCD_SECTORDAMAGE", + "PCD_REPLACETEXTURES", + "PCD_NEGATEBINARY", + "PCD_GETACTORPITCH", + "PCD_SETACTORPITCH", + "PCD_PRINTBIND", + "PCD_SETACTORSTATE", + "PCD_THINGDAMAGE2", + "PCD_USEINVENTORY", + "PCD_USEACTORINVENTORY", + "PCD_CHECKACTORCEILINGTEXTURE", + "PCD_CHECKACTORFLOORTEXTURE", + "PCD_GETACTORLIGHTLEVEL", + "PCD_SETMUGSHOTSTATE", + "PCD_THINGCOUNTSECTOR", + "PCD_THINGCOUNTNAMESECTOR", + "PCD_CHECKPLAYERCAMERA", + "PCD_MORPHACTOR", + "PCD_UNMORPHACTOR", + "PCD_GETPLAYERINPUT", + "PCD_CLASSIFYACTOR", + "PCD_PRINTBINARY", + "PCD_PRINTHEX", + "PCD_CALLFUNC", + "PCD_SAVESTRING", // [FDARI] + "PCD_PRINTMAPCHRANGE", // [FDARI] output range + "PCD_PRINTWORLDCHRANGE", + "PCD_PRINTGLOBALCHRANGE", + "PCD_STRCPYTOMAPCHRANGE", // [FDARI] input range + "PCD_STRCPYTOWORLDCHRANGE", + "PCD_STRCPYTOGLOBALCHRANGE", + "PCD_PUSHFUNCTION", // from Eternity + "PCD_CALLSTACK", // from Eternity + "PCD_SCRIPTWAITNAMED", + "PCD_TRANSLATIONRANGE3", + "PCD_GOTOSTACK", + "PCD_ASSIGNSCRIPTARRAY", + "PCD_PUSHSCRIPTARRAY", + "PCD_ADDSCRIPTARRAY", + "PCD_SUBSCRIPTARRAY", + "PCD_MULSCRIPTARRAY", + "PCD_DIVSCRIPTARRAY", + "PCD_MODSCRIPTARRAY", + "PCD_INCSCRIPTARRAY", + "PCD_DECSCRIPTARRAY", + "PCD_ANDSCRIPTARRAY", + "PCD_EORSCRIPTARRAY", + "PCD_ORSCRIPTARRAY", + "PCD_LSSCRIPTARRAY", + "PCD_RSSCRIPTARRAY", + "PCD_PRINTSCRIPTCHARARRAY", + "PCD_PRINTSCRIPTCHRANGE", + "PCD_STRCPYTOSCRIPTCHRANGE", + "PCD_LSPEC5EX", + "PCD_LSPEC5EXRESULT", +}; + +// CODE -------------------------------------------------------------------- + +//========================================================================== +// +// PC_OpenObject +// +//========================================================================== + +void PC_OpenObject(char *name, size_t size, int flags) +{ + if(ObjectOpened == YES) + { + PC_CloseObject(); + } + if(strlen(name) >= MAX_FILE_NAME_LENGTH) + { + ERR_Exit(ERR_FILE_NAME_TOO_LONG, NO, name); + } + strcpy(ObjectName, name); + pc_Buffer = MS_Alloc(size, ERR_ALLOC_PCODE_BUFFER); + pc_BufferPtr = pc_Buffer; + pc_Address = 0; + ObjectFlags = flags; + BufferSize = size; + pc_ScriptCount = 0; + ObjectOpened = YES; + PC_AppendString("ACS"); + PC_SkipInt(); // Script table offset +} + +//========================================================================== +// +// PC_CloseObject +// +//========================================================================== + +void PC_CloseObject(void) +{ + MS_Message(MSG_DEBUG, "---- PC_CloseObject ----\n"); + while (pc_Address & 3) + { + PC_AppendByte (0); + } + if(!pc_NoShrink || (NumStringLists > 0) || + (pc_FunctionCount > 0) || MapVariablesInit || NumArrays != 0 || + pc_EncryptStrings || NumImports != 0 || HaveExtendedScripts || + HaveScriptArrays) + { + if(pc_EnforceHexen) + { + ERR_Exit(ERR_NOT_HEXEN, NO); + } + if(pc_WarnNotHexen) + { + fprintf(stderr, "\nThese scripts have been upgraded because they use new features.\n" + "They will not be compatible with Hexen.\n"); + } + CloseNew(); + } + else + { + CloseOld(); + } + if(MS_SaveFile(ObjectName, pc_Buffer, pc_Address) == FALSE) + { + ERR_Exit(ERR_SAVE_OBJECT_FAILED, NO); + } +} + +//========================================================================== +// +// CloseOld +// +//========================================================================== + +static void CloseOld(void) +{ + int i; + + STR_WriteStrings(); + PC_WriteInt((U_INT)pc_Address, 4); + PC_AppendInt((U_INT)pc_ScriptCount); + for(i = 0; i < pc_ScriptCount; ++i) + { + scriptInfo_t *info = &ScriptInfo[i]; + MS_Message(MSG_DEBUG, "Script %d, address = %d, arg count = %d\n", + info->number, info->address, info->argCount); + PC_AppendInt((U_INT)(info->number + info->type * 1000)); + PC_AppendInt((U_INT)info->address); + PC_AppendInt((U_INT)info->argCount); + } + STR_WriteList(); +} + +//========================================================================== +// +// CloseNew +// +// Creates a new-format ACS file. For programs that don't know any better, +// this will look just like an old ACS file with no scripts or strings but +// with some extra junk in the middle. Both WadAuthor and DeePsea will not +// accept ACS files that do not have the ACS\0 header. Worse, WadAuthor +// will hang if the file begins with ACS\0 but does not look like something +// that might have been created with Raven's ACC. Thus, the chunks live in +// the string block, and there are two 0 dwords at the end of the file. +// +//========================================================================== + +static void CloseNew(void) +{ + int i, j, count; + int chunkStart; + + if(pc_WadAuthor) + { + CreateDummyScripts(); + } + + chunkStart = pc_Address; + + // Only write out those scripts that this acs file actually provides. + for(i = j = 0; i < pc_ScriptCount; ++i) + { + if(!ScriptInfo[i].imported) + { + ++j; + } + } + if(j > 0) + { + PC_Append("SPTR", 4); + PC_AppendInt(j * 8); + for(i = 0; i < pc_ScriptCount; i++) + { + scriptInfo_t *info = &ScriptInfo[i]; + if(!info->imported) + { + MS_Message(MSG_DEBUG, "Script %d, address = %d, arg count = %d\n", + info->number, info->address, info->argCount); + PC_AppendWord(info->number); + PC_AppendByte(info->type); + PC_AppendByte(info->argCount); + PC_AppendInt((U_INT)info->address); + } + } + } + + // If any scripts have more than the maximum number of arguments, output them. + for(i = j = 0; i < pc_ScriptCount; ++i) + { + if(!ScriptInfo[i].imported && ScriptInfo[i].varCount > MAX_SCRIPT_VARIABLES) + { + ++j; + } + } + if(j > 0) + { + PC_Append("SVCT", 4); + PC_AppendInt(j * 4); + for(i = 0; i < pc_ScriptCount; ++i) + { + scriptInfo_t *info = &ScriptInfo[i]; + if(!info->imported && info->varCount > MAX_SCRIPT_VARIABLES) + { + MS_Message(MSG_DEBUG, "Script %d, var count = %d\n", + info->number, info->varCount); + PC_AppendWord(info->number); + PC_AppendWord(info->varCount); + } + } + } + + // Write script flags in a separate chunk, so older ZDooms don't get confused + for(i = j = 0; i < pc_ScriptCount; ++i) + { + if(!ScriptInfo[i].imported && ScriptInfo[i].flags != 0) + { + ++j; + } + } + if (j > 0) + { + PC_Append("SFLG", 4); + PC_AppendInt(j * 4); + for(i = 0; i < pc_ScriptCount; ++i) + { + scriptInfo_t *info = &ScriptInfo[i]; + if(!info->imported && info->flags != 0) + { + PC_AppendWord(info->number); + PC_AppendWord(info->flags); + } + } + } + + // Add chunks for scripts with arrays + for(i = 0; i < pc_ScriptCount; ++i) + { + if(ScriptInfo[i].arrayCount) + { + PC_Append("SARY", 4); + PC_AppendInt(2 + ScriptInfo[i].arrayCount * 4); + PC_AppendWord(ScriptInfo[i].number); + for(j = 0; j < ScriptInfo[i].arrayCount; ++j) + { + PC_AppendInt(ScriptInfo[i].arraySizes[j]); + } + } + } + + // Write the string table for named scripts. + STR_WriteListChunk(STRLIST_NAMEDSCRIPTS, MAKE4CC('S','N','A','M'), NO); + + // Write the functions provided by this file. + if(pc_FunctionCount > 0) + { + PC_Append("FUNC", 4); + PC_AppendInt(pc_FunctionCount * 8); + for(i = 0; i < pc_FunctionCount; ++i) + { + functionInfo_t *info = &FunctionInfo[i]; + MS_Message(MSG_DEBUG, "Function %d:%s, address = %d, arg count = %d, var count = %d\n", + i, STR_GetString(STRLIST_FUNCTIONS, info->name), + info->address, info->argCount, info->localCount); + PC_AppendByte(info->argCount); + PC_AppendByte(info->localCount); + PC_AppendByte((U_BYTE)(info->hasReturnValue?1:0)); + PC_AppendByte(0); + PC_AppendInt((U_INT)info->address); + } + STR_WriteListChunk(STRLIST_FUNCTIONS, MAKE4CC('F','N','A','M'), NO); + } + + // Add chunks for functions with arrays + for(i = 0; i < pc_FunctionCount; ++i) + { + if(FunctionInfo[i].arrayCount) + { + PC_Append("FARY", 4); + PC_AppendInt(2 + FunctionInfo[i].arrayCount * 4); + PC_AppendWord((U_WORD)i); + for(j = 0; j < FunctionInfo[i].arrayCount; ++j) + { + PC_AppendInt(FunctionInfo[i].arraySizes[j]); + } + } + } + + + if(STR_ListSize() > 0) + { + STR_WriteChunk(pc_EncryptStrings); + } + + STR_WriteListChunk(STRLIST_PICS, MAKE4CC('P','I','C','S'), NO); + if(MapVariablesInit) + { + int j; + + for(i = 0; i < pa_MapVarCount; ++i) + { + if(MapVariables[i].initializer != 0) + break; + } + for(j = pa_MapVarCount-1; j > i; --j) + { + if(MapVariables[j].initializer != 0) + break; + } + ++j; + + if (i < j) + { + PC_Append("MINI", 4); + PC_AppendInt((j-i)*4+4); + PC_AppendInt(i); // First map var defined + for(; i < j; ++i) + { + PC_AppendInt(MapVariables[i].initializer); + } + } + } + + // If this is a library, record which map variables are + // initialized with strings. + if(ImportMode == IMPORT_Exporting) + { + count = 0; + + for(i = 0; i < pa_MapVarCount; ++i) + { + if(MapVariables[i].isString) + { + ++count; + } + } + if(count > 0) + { + PC_Append("MSTR", 4); + PC_AppendInt(count*4); + for(i = 0; i < pa_MapVarCount; ++i) + { + if(MapVariables[i].isString) + { + PC_AppendInt(i); + } + } + } + + // Now do the same thing for arrays. + for(count = 0, i = 0; i < pa_MapVarCount; ++i) + { + if(ArrayOfStrings[i]) + { + ++count; + } + } + if(count > 0) + { + PC_Append("ASTR", 4); + PC_AppendInt(count*4); + for(i = 0; i < pa_MapVarCount; ++i) + { + if(ArrayOfStrings[i]) + { + PC_AppendInt(i); + } + } + } + } + + // Publicize the names of map variables in a library. + if(ImportMode == IMPORT_Exporting) + { + for(i = 0; i < pa_MapVarCount; ++i) + { + if(!MapVariables[i].imported) + { + STR_AppendToList(STRLIST_MAPVARS, MapVariables[i].name); + } + else + { + STR_AppendToList(STRLIST_MAPVARS, NULL); + } + } + STR_WriteListChunk(STRLIST_MAPVARS, MAKE4CC('M','E','X','P'), NO); + } + + // Record the names of imported map variables + count = 0; + for(i = 0; i < pa_MapVarCount; ++i) + { + if(MapVariables[i].imported && !ArraySizes[i]) + { + count += 5 + strlen(MapVariables[i].name); + } + } + if(count > 0) + { + PC_Append("MIMP", 4); + PC_AppendInt(count); + for(i = 0; i < pa_MapVarCount; ++i) + { + if(MapVariables[i].imported && !ArraySizes[i]) + { + PC_AppendInt(i); + PC_AppendString(MapVariables[i].name); + } + } + } + + if(NumArrays) + { + int count; + + // Arrays defined here + for(count = 0, i = 0; i < pa_MapVarCount; ++i) + { + if(ArraySizes[i] && !MapVariables[i].imported) + { + ++count; + } + } + if(count) + { + PC_Append("ARAY", 4); + PC_AppendInt(count*8); + for(i = 0; i < pa_MapVarCount; ++i) + { + if(ArraySizes[i] && !MapVariables[i].imported) + { + PC_AppendInt(i); + PC_AppendInt(ArraySizes[i]); + } + } + for(i = 0; i < pa_MapVarCount; ++i) + { + if(ArrayInits[i]) + { + int j; + + PC_Append("AINI", 4); + PC_AppendInt(ArraySizes[i]*4+4); + PC_AppendInt((U_INT)i); + MS_Message(MSG_DEBUG, "Writing array initializers for array %d (size %d)\n", i, ArraySizes[i]); + for(j = 0; j < ArraySizes[i]; ++j) + { + PC_AppendInt((U_INT)ArrayInits[i][j]); + } + } + } + } + + // Arrays imported from elsewhere + for(count = 0, j = i = 0; i < pa_MapVarCount; ++i) + { + if(ArraySizes[i] && MapVariables[i].imported) + { + count += 9 + strlen(MapVariables[i].name); + ++j; + } + } + if(count) + { + PC_Append("AIMP", 4); + PC_AppendInt(count+4); + PC_AppendInt(j); + for(i = 0; i < pa_MapVarCount; ++i) + { + if(ArraySizes[i] && MapVariables[i].imported) + { + PC_AppendInt(i); + PC_AppendInt(ArraySizes[i]); + PC_AppendString(MapVariables[i].name); + } + } + } + } + + // Add a dummy chunk to indicate if this object is a library. + if(ImportMode == IMPORT_Exporting) + { + PC_Append("ALIB", 4); + PC_AppendInt(0); + } + + // Record libraries imported by this object. + if(NumImports > 0) + { + count = 0; + for(i = 0; i < NumImports; ++i) + { + count += strlen(Imports[i]) + 1; + } + if(count > 0) + { + PC_Append("LOAD", 4); + PC_AppendInt(count); + for(i = 0; i < NumImports; ++i) + { + PC_AppendString(Imports[i]); + } + } + } + + PC_AppendInt((U_INT)chunkStart); + if(pc_NoShrink) + { + PC_Append("ACSE", 4); + } + else + { + PC_Append("ACSe", 4); + } + PC_WriteInt((U_INT)pc_Address, 4); + + // WadAuthor compatibility when creating a library is pointless, because + // that editor does not know anything about libraries and will never + // find their scripts ever. + if(pc_WadAuthor && ImportMode != IMPORT_Exporting) + { + RecordDummyScripts(); + } + else + { + PC_AppendInt(0); + } + PC_AppendInt(0); +} + +//========================================================================== +// +// CreateDummyScripts +// +//========================================================================== + +static void CreateDummyScripts(void) +{ + int i; + + MS_Message(MSG_DEBUG, "Creating dummy scripts to make WadAuthor happy.\n"); + if(pc_Address%4 != 0) + { // Need to align + U_INT pad = 0; + PC_Append((void *)&pad, 4-(pc_Address%4)); + } + pc_DummyAddress = pc_Address; + for(i = 0; i < pc_ScriptCount; ++i) + { + // Only create dummies for scripts WadAuthor could care about. + if(!ScriptInfo[i].imported && ScriptInfo[i].number >= 0 && ScriptInfo[i].number <= 255) + { + PC_AppendCmd(PCD_TERMINATE); + if(!pc_NoShrink) + { + PC_AppendCmd(PCD_NOP); + PC_AppendCmd(PCD_NOP); + PC_AppendCmd(PCD_NOP); + } + } + } +} + +//========================================================================== +// +// RecordDummyScripts +// +//========================================================================== + +static void RecordDummyScripts(void) +{ + int i, j, count; + + for(i = count = 0; i < pc_ScriptCount; ++i) + { + if(!ScriptInfo[i].imported && ScriptInfo[i].number >= 0 && ScriptInfo[i].number <= 255) + { + ++count; + } + } + PC_AppendInt((U_INT)count); + for(i = j = 0; i < pc_ScriptCount; ++i) + { + scriptInfo_t *info = &ScriptInfo[i]; + if(!info->imported && info->number >= 0 && ScriptInfo[i].number <= 255) + { + MS_Message(MSG_DEBUG, "Dummy script %d, address = %d, arg count = %d\n", + info->number, info->address, info->argCount); + PC_AppendInt((U_INT)info->number); + PC_AppendInt((U_INT)pc_DummyAddress + j*4); + PC_AppendInt((U_INT)info->argCount); + j++; + } + } +} + +//========================================================================== +// +// GrowBuffer +// +//========================================================================== + +void GrowBuffer(void) +{ + ptrdiff_t buffpos = pc_BufferPtr - pc_Buffer; + + BufferSize *= 2; + pc_Buffer = MS_Realloc(pc_Buffer, BufferSize, ERR_PCODE_BUFFER_OVERFLOW); + pc_BufferPtr = pc_Buffer + buffpos; +} + +//========================================================================== +// +// PC_Append functions +// +//========================================================================== + +static void Append(void *buffer, size_t size) +{ + if (ImportMode != IMPORT_Importing) + { + if(pc_Address+size > BufferSize) + { + GrowBuffer (); + } + memcpy(pc_BufferPtr, buffer, size); + pc_BufferPtr += size; + pc_Address += size; + } +} + +void PC_Append(void *buffer, size_t size) +{ + if (ImportMode != IMPORT_Importing) + { + MS_Message(MSG_DEBUG, "AD> %06d = (%d bytes)\n", pc_Address, size); + Append(buffer, size); + } +} + +void PC_AppendByte(U_BYTE val) +{ + if (ImportMode != IMPORT_Importing) + { + MS_Message(MSG_DEBUG, "AB> %06d = %d\n", pc_Address, val); + Append(&val, sizeof(U_BYTE)); + } +} + +void PC_AppendWord(U_WORD val) +{ + if (ImportMode != IMPORT_Importing) + { + MS_Message(MSG_DEBUG, "AW> %06d = %d\n", pc_Address, val); + val = MS_LittleUWORD(val); + Append(&val, sizeof(U_WORD)); + } +} + +void PC_AppendInt(U_INT val) +{ + if (ImportMode != IMPORT_Importing) + { + MS_Message(MSG_DEBUG, "AL> %06d = %d\n", pc_Address, val); + val = MS_LittleUINT(val); + Append(&val, sizeof(U_INT)); + } +} + +void PC_AppendString(char *string) +{ + if (ImportMode != IMPORT_Importing) + { + int length; + + length = strlen(string)+1; + MS_Message(MSG_DEBUG, "AS> %06d = \"%s\" (%d bytes)\n", + pc_Address, string, length); + Append(string, length); + } +} + +void PC_AppendCmd(pcd_t command) +{ + boolean dupbyte = NO; + if (ImportMode != IMPORT_Importing) + { + pc_LastAppendedCommand = command; + if (pc_NoShrink) + { + MS_Message(MSG_DEBUG, "AC> %06d = #%d:%s\n", pc_Address, + command, PCDNames[command]); + command = MS_LittleUINT(command); + Append(&command, sizeof(U_INT)); + } + else + { + U_BYTE cmd; + if (command == PCD_DUP && PushByteAddr) + { // If the last instruction was PCD_PUSHBYTE, convert this PCD_DUP to a + // duplicate PCD_PUSHBYTE, so it can be merged into a single instruction below. + command = PCD_PUSHBYTE; + dupbyte = YES; + MS_Message(MSG_DEBUG, "AC> PCD_DUP changed to PCD_PUSHBYTE\n"); + } + else if (command != PCD_PUSHBYTE && PushByteAddr) + { // Maybe shrink a PCD_PUSHBYTE sequence into PCD_PUSHBYTES + int runlen = (pc_Address - PushByteAddr) / 2; + int i; + + if (runlen > 5) + { + pc_Buffer[PushByteAddr] = PCD_PUSHBYTES; + for (i = 0; i < runlen; i++) + { + pc_Buffer[PushByteAddr+i+2] = pc_Buffer[PushByteAddr+i*2+1]; + } + pc_Buffer[PushByteAddr+1] = runlen; + pc_Address = PushByteAddr + runlen + 2; + pc_BufferPtr = pc_Buffer + pc_Address; + MS_Message(MSG_DEBUG, "AC> Last %d PCD_PUSHBYTEs changed to #%d:PCD_PUSHBYTES\n", + runlen, PCD_PUSHBYTES); + } + else if (runlen > 1) + { + pc_Buffer[PushByteAddr] = PCD_PUSH2BYTES + runlen - 2; + for (i = 1; i < runlen; i++) + { + pc_Buffer[PushByteAddr+1+i] = pc_Buffer[PushByteAddr+1+i*2]; + } + pc_Address = PushByteAddr + runlen + 1; + pc_BufferPtr = pc_Buffer + pc_Address; + MS_Message(MSG_DEBUG, "AC> Last %d PCD_PUSHBYTEs changed to #%d:PCD_PUSH%dBYTES\n", + runlen, PCD_PUSH2BYTES+runlen-2, runlen); + } + PushByteAddr = 0; + } + else if(command == PCD_PUSHBYTE && PushByteAddr == 0) + { // Remember the first PCD_PUSHBYTE, in case there are more + PushByteAddr = pc_Address; + } + MS_Message(MSG_DEBUG, "AC> %06d = #%d:%s\n", pc_Address, + command, PCDNames[command]); + + if (command < 256-16) + { + cmd = command; + Append(&cmd, sizeof(U_BYTE)); + } + else + { + // Room for expansion: The top 16 pcodes in the [0,255] + // range select a set of pcodes, and the next byte is + // the pcode in that set. + cmd = ((command - (256-16)) >> 8) + (256-16); + Append(&cmd, sizeof(U_BYTE)); + cmd = (command - (256-16)) & 255; + Append(&cmd, sizeof(U_BYTE)); + } + if (dupbyte) + { + PC_AppendByte(pc_Buffer[pc_Address-2]); + } + } + } +} + +//========================================================================== +// +// PC_AppendShrink +// +//========================================================================== + +void PC_AppendShrink(U_BYTE val) +{ + if(pc_NoShrink) + { + PC_AppendInt(val); + } + else + { + PC_AppendByte(val); + } +} + +//========================================================================== +// +// PC_AppendPushVal +// +//========================================================================== + +void PC_AppendPushVal(U_INT val) +{ + if(pc_NoShrink || val > 255) + { + PC_AppendCmd(PCD_PUSHNUMBER); + PC_AppendInt(val); + } + else + { + PC_AppendCmd(PCD_PUSHBYTE); + PC_AppendByte((U_BYTE)val); + } +} + +//========================================================================== +// +// PC_Write functions +// +//========================================================================== + +static void Write(void *buffer, size_t size, int address) +{ + if (ImportMode != IMPORT_Importing) + { + if(address+size > BufferSize) + { + GrowBuffer(); + } + memcpy(pc_Buffer+address, buffer, size); + } +} + +void PC_Write(void *buffer, size_t size, int address) +{ + if (ImportMode != IMPORT_Importing) + { + MS_Message(MSG_DEBUG, "WD> %06d = (%d bytes)\n", address, size); + Write(buffer, size, address); + } +} + +void PC_WriteByte(U_BYTE val, int address) +{ + if (ImportMode != IMPORT_Importing) + { + MS_Message(MSG_DEBUG, "WB> %06d = %d\n", address, val); + Write(&val, sizeof(U_BYTE), address); + } +} + +/* +void PC_WriteWord(U_WORD val, int address) +{ + MS_Message(MSG_DEBUG, "WW> %06d = %d\n", address, val); + val = MS_LittleUWORD(val); + Write(&val, sizeof(U_WORD), address); +} +*/ + +void PC_WriteInt(U_INT val, int address) +{ + if (ImportMode != IMPORT_Importing) + { + MS_Message(MSG_DEBUG, "WL> %06d = %d\n", address, val); + val = MS_LittleUINT(val); + Write(&val, sizeof(U_INT), address); + } + pc_LastAppendedCommand = PCD_NOP; +} + +void PC_WriteString(char *string, int address) +{ + if (ImportMode != IMPORT_Importing) + { + int length; + + length = strlen(string)+1; + MS_Message(MSG_DEBUG, "WS> %06d = \"%s\" (%d bytes)\n", + address, string, length); + Write(string, length, address); + } +} + +void PC_WriteCmd(pcd_t command, int address) +{ + if (ImportMode != IMPORT_Importing) + { + MS_Message(MSG_DEBUG, "WC> %06d = #%d:%s\n", address, + command, PCDNames[command]); + command = MS_LittleUINT(command); + Write(&command, sizeof(U_INT), address); + } +} + +//========================================================================== +// +// PC_Skip functions +// +//========================================================================== + +static void Skip(size_t size) +{ + if (ImportMode != IMPORT_Importing) + { + if(pc_Address+size > BufferSize) + { + GrowBuffer(); + } + pc_BufferPtr += size; + pc_Address += size; + } +} + +void PC_Skip(size_t size) +{ + if (ImportMode != IMPORT_Importing) + { + MS_Message(MSG_DEBUG, "SD> %06d (skip %d bytes)\n", pc_Address, size); + Skip(size); + } +} + +/* +void PC_SkipByte(void) +{ + MS_Message(MSG_DEBUG, "SB> %06d (skip byte)\n", pc_Address); + Skip(sizeof(U_BYTE)); +} +*/ + +/* +void PC_SkipWord(void) +{ + MS_Message(MSG_DEBUG, "SW> %06d (skip word)\n", pc_Address); + Skip(sizeof(U_WORD)); +} +*/ + +void PC_SkipInt(void) +{ + if (ImportMode != IMPORT_Importing) + { + MS_Message(MSG_DEBUG, "SL> %06d (skip int)\n", pc_Address); + Skip(sizeof(U_INT)); + } +} + +//========================================================================== +// +// PC_PutMapVariable +// +//========================================================================== + +void PC_PutMapVariable(int index, int value) +{ + if(index < MAX_MAP_VARIABLES) + { + MapVariables[index].isString = pa_ConstExprIsString; + MapVariables[index].initializer = value; + MapVariablesInit = YES; + if(pc_EnforceHexen) + { + ERR_Error(ERR_HEXEN_COMPAT, YES); + } + } +} + +//========================================================================== +// +// PC_NameMapVariable +// +//========================================================================== + +void PC_NameMapVariable(int index, symbolNode_t *sym) +{ + if(index < MAX_MAP_VARIABLES) + { + MapVariables[index].name = sym->name; + MapVariables[index].imported = sym->imported; + } +} + +//========================================================================== +// +// PC_AddScript +// +//========================================================================== + +void PC_AddScript(int number, int type, int flags, int argCount) +{ + scriptInfo_t *script; + int i; + + if (flags != 0 || number < 0 || number >= 1000) + { + HaveExtendedScripts = YES; + if(pc_EnforceHexen) + { + ERR_Error(ERR_HEXEN_COMPAT, YES); + } + } + + for (i = 0; i < pc_ScriptCount; i++) + { + if (ScriptInfo[i].number == number) + { + ERR_Error(ERR_SCRIPT_ALREADY_DEFINED, YES); + } + } + if(pc_ScriptCount == MAX_SCRIPT_COUNT) + { + ERR_Error(ERR_TOO_MANY_SCRIPTS, YES); + } + else + { + script = &ScriptInfo[pc_ScriptCount]; + script->number = number; + script->type = type; + script->address = (ImportMode == IMPORT_Importing) ? 0 : pc_Address; + script->argCount = argCount; + script->flags = flags; + script->srcLine = tk_Line; + script->imported = (ImportMode == IMPORT_Importing) ? YES : NO; + script->arrayCount = 0; + pc_ScriptCount++; + } +} + +//========================================================================== +// +// PC_SetScriptVarCount +// +// Sets the number of local variables used by a script, including +// arguments. +// +//========================================================================== + +void PC_SetScriptVarCount(int number, int type, int varCount, int arrayCount, int *arraySizes) +{ + int i; + + for(i = 0; i < pc_ScriptCount; i++) + { + if(ScriptInfo[i].number == number && ScriptInfo[i].type == type) + { + ScriptInfo[i].varCount = varCount; + if (arrayCount > 0 && arrayCount < MAX_SCRIPT_ARRAYS) + { + ScriptInfo[i].arrayCount = (U_BYTE)arrayCount; + memcpy(ScriptInfo[i].arraySizes, arraySizes, arrayCount * sizeof(int)); + HaveScriptArrays = YES; + } + break; + } + } +} + +//========================================================================== +// +// PC_AddFunction +// +//========================================================================== + +void PC_AddFunction(symbolNode_t *sym, int arrayCount, int *arraySizes) +{ + functionInfo_t *function; + int maxFunctionCount = pc_NoShrink ? MAX_FUNCTION_COUNT : (1 << CHAR_BIT * sizeof(U_BYTE)); + + if(pc_FunctionCount == maxFunctionCount) + { + ERR_Error(ERR_TOO_MANY_FUNCTIONS, YES, NULL); + } + function = &FunctionInfo[pc_FunctionCount]; + function->hasReturnValue = (U_BYTE)sym->info.scriptFunc.hasReturnValue; + function->argCount = (U_BYTE)sym->info.scriptFunc.argCount; + function->localCount = (U_BYTE)sym->info.scriptFunc.varCount; + function->name = STR_AppendToList (STRLIST_FUNCTIONS, sym->name); + function->address = sym->info.scriptFunc.address; + sym->info.scriptFunc.funcNumber = pc_FunctionCount; + if (arrayCount > 0 && arrayCount < MAX_SCRIPT_ARRAYS) + { + function->arrayCount = (U_BYTE)arrayCount; + memcpy(function->arraySizes, arraySizes, arrayCount * sizeof(int)); + HaveScriptArrays = YES; + } + else + { + function->arrayCount = 0; + } + pc_FunctionCount++; +} + +//========================================================================== +// +// PC_AddArray +// +//========================================================================== + +void PC_AddArray(int index, int size) +{ + NumArrays++; + ArraySizes[index] = size; + if(pc_EnforceHexen) + { + ERR_Error(ERR_HEXEN_COMPAT, YES); + } +} + +//========================================================================== +// +// PC_InitArray +// +//========================================================================== + +void PC_InitArray(int index, int *entries, boolean hasStrings) +{ + int i; + + // If the array is just initialized to zeros, then we don't need to + // remember the initializer. + for(i = 0; i < ArraySizes[index]; ++i) + { + if(entries[i] != 0) + { + break; + } + } + if(i < ArraySizes[index]) + { + ArrayInits[index] = MS_Alloc(ArraySizes[index]*sizeof(int), ERR_OUT_OF_MEMORY); + memcpy(ArrayInits[index], entries, ArraySizes[index]*sizeof(int)); + } + ArrayOfStrings[index] = hasStrings; +} + +//========================================================================== +// +// PC_AddImport +// +//========================================================================== + +int PC_AddImport(char *name) +{ + if (NumImports >= MAX_IMPORTS) + { + ERR_Exit(ERR_TOO_MANY_IMPORTS, YES); + } + else if(pc_EnforceHexen) + { + ERR_Error(ERR_HEXEN_COMPAT, YES); + } + strncpy(Imports[NumImports], name, 8); + return NumImports++; +} diff --git a/pcode.h b/pcode.h index 8c10ec3..715807e 100644 --- a/pcode.h +++ b/pcode.h @@ -1,503 +1,503 @@ - -//************************************************************************** -//** -//** pcode.h -//** -//************************************************************************** - -#ifndef __PCODE_H__ -#define __PCODE_H__ - -// HEADER FILES ------------------------------------------------------------ - -#include -#include "common.h" - -// MACROS ------------------------------------------------------------------ - -// Values to indicate a script's type -enum -{ - OPEN_SCRIPTS_BASE = 1, - RESPAWN_SCRIPTS_BASE = 2, // [BC] - DEATH_SCRIPTS_BASE = 3, // [BC] - ENTER_SCRIPTS_BASE = 4, // [BC] - PICKUP_SCRIPTS_BASE = 5, // [BC] - BLUE_RETURN_SCRIPTS_BASE = 6, // [BC] - RED_RETURN_SCRIPTS_BASE = 7, // [BC] - WHITE_RETURN_SCRIPTS_BASE = 8, // [BC] - LIGHTNING_SCRIPTS_BASE = 12, - UNLOADING_SCRIPTS_BASE = 13, - DISCONNECT_SCRIPTS_BASE = 14, - RETURN_SCRIPTS_BASE = 15, - EVENT_SCRIPTS_BASE = 16, // [BB] - KILL_SCRIPTS_BASE = 17, // [JM] - REOPEN_SCRIPTS_BASE = 18, // [Nash] -}; - -// Values to indicate script flags (requires new-style .o) -enum -{ - NET_SCRIPT_FLAG = 0x0001, - CLIENTSIDE_SCRIPT_FLAG = 0x0002, // [BB] -}; - -// Or'ed with variable index when passing variables of type "out" -// An idea that was never realized. -enum -{ - OUTVAR_SCRIPT_SPEC = 0x40000000, - OUTVAR_MAP_SPEC = 0x80000000, - OUTVAR_WORLD_SPEC = 0xc0000000, - OUTVAR_GLOBAL_SPEC = 0x00000000 -}; - -// TYPES ------------------------------------------------------------------- - -struct symbolNode_s; // Defined in symbol.h - -typedef enum -{ - PCD_NOP, - PCD_TERMINATE, - PCD_SUSPEND, - PCD_PUSHNUMBER, - PCD_LSPEC1, - PCD_LSPEC2, - PCD_LSPEC3, - PCD_LSPEC4, - PCD_LSPEC5, - PCD_LSPEC1DIRECT, - PCD_LSPEC2DIRECT, - PCD_LSPEC3DIRECT, - PCD_LSPEC4DIRECT, - PCD_LSPEC5DIRECT, - PCD_ADD, - PCD_SUBTRACT, - PCD_MULTIPLY, - PCD_DIVIDE, - PCD_MODULUS, - PCD_EQ, - PCD_NE, - PCD_LT, - PCD_GT, - PCD_LE, - PCD_GE, - PCD_ASSIGNSCRIPTVAR, - PCD_ASSIGNMAPVAR, - PCD_ASSIGNWORLDVAR, - PCD_PUSHSCRIPTVAR, - PCD_PUSHMAPVAR, - PCD_PUSHWORLDVAR, - PCD_ADDSCRIPTVAR, - PCD_ADDMAPVAR, - PCD_ADDWORLDVAR, - PCD_SUBSCRIPTVAR, - PCD_SUBMAPVAR, - PCD_SUBWORLDVAR, - PCD_MULSCRIPTVAR, - PCD_MULMAPVAR, - PCD_MULWORLDVAR, - PCD_DIVSCRIPTVAR, - PCD_DIVMAPVAR, - PCD_DIVWORLDVAR, - PCD_MODSCRIPTVAR, - PCD_MODMAPVAR, - PCD_MODWORLDVAR, - PCD_INCSCRIPTVAR, - PCD_INCMAPVAR, - PCD_INCWORLDVAR, - PCD_DECSCRIPTVAR, - PCD_DECMAPVAR, - PCD_DECWORLDVAR, - PCD_GOTO, - PCD_IFGOTO, - PCD_DROP, - PCD_DELAY, - PCD_DELAYDIRECT, - PCD_RANDOM, - PCD_RANDOMDIRECT, - PCD_THINGCOUNT, - PCD_THINGCOUNTDIRECT, - PCD_TAGWAIT, - PCD_TAGWAITDIRECT, - PCD_POLYWAIT, - PCD_POLYWAITDIRECT, - PCD_CHANGEFLOOR, - PCD_CHANGEFLOORDIRECT, - PCD_CHANGECEILING, - PCD_CHANGECEILINGDIRECT, - PCD_RESTART, - PCD_ANDLOGICAL, - PCD_ORLOGICAL, - PCD_ANDBITWISE, - PCD_ORBITWISE, - PCD_EORBITWISE, - PCD_NEGATELOGICAL, - PCD_LSHIFT, - PCD_RSHIFT, - PCD_UNARYMINUS, - PCD_IFNOTGOTO, - PCD_LINESIDE, - PCD_SCRIPTWAIT, - PCD_SCRIPTWAITDIRECT, - PCD_CLEARLINESPECIAL, - PCD_CASEGOTO, - PCD_BEGINPRINT, - PCD_ENDPRINT, - PCD_PRINTSTRING, - PCD_PRINTNUMBER, - PCD_PRINTCHARACTER, - PCD_PLAYERCOUNT, - PCD_GAMETYPE, - PCD_GAMESKILL, - PCD_TIMER, - PCD_SECTORSOUND, - PCD_AMBIENTSOUND, - PCD_SOUNDSEQUENCE, - PCD_SETLINETEXTURE, - PCD_SETLINEBLOCKING, - PCD_SETLINESPECIAL, - PCD_THINGSOUND, - PCD_ENDPRINTBOLD, -// [RH] End of Hexen p-codes - PCD_ACTIVATORSOUND, - PCD_LOCALAMBIENTSOUND, - PCD_SETLINEMONSTERBLOCKING, -// [BC] Start of new pcodes - PCD_PLAYERBLUESKULL, - PCD_PLAYERREDSKULL, - PCD_PLAYERYELLOWSKULL, - PCD_PLAYERMASTERSKULL, - PCD_PLAYERBLUECARD, - PCD_PLAYERREDCARD, - PCD_PLAYERYELLOWCARD, - PCD_PLAYERMASTERCARD, - PCD_PLAYERBLACKSKULL, - PCD_PLAYERSILVERSKULL, - PCD_PLAYERGOLDSKULL, - PCD_PLAYERBLACKCARD, - PCD_PLAYERSILVERCARD, - PCD_ISNETWORKGAME, - PCD_PLAYERTEAM, - PCD_PLAYERHEALTH, - PCD_PLAYERARMORPOINTS, - PCD_PLAYERFRAGS, - PCD_PLAYEREXPERT, - PCD_BLUETEAMCOUNT, - PCD_REDTEAMCOUNT, - PCD_BLUETEAMSCORE, - PCD_REDTEAMSCORE, - PCD_ISONEFLAGCTF, - PCD_GETINVASIONWAVE, - PCD_GETINVASIONSTATE, - PCD_PRINTNAME, - PCD_MUSICCHANGE, - PCD_CONSOLECOMMANDDIRECT, - PCD_CONSOLECOMMAND, - PCD_SINGLEPLAYER, -// [RH] End of Skull Tag p-codes - PCD_FIXEDMUL, - PCD_FIXEDDIV, - PCD_SETGRAVITY, - PCD_SETGRAVITYDIRECT, - PCD_SETAIRCONTROL, - PCD_SETAIRCONTROLDIRECT, - PCD_CLEARINVENTORY, - PCD_GIVEINVENTORY, - PCD_GIVEINVENTORYDIRECT, - PCD_TAKEINVENTORY, - PCD_TAKEINVENTORYDIRECT, - PCD_CHECKINVENTORY, - PCD_CHECKINVENTORYDIRECT, - PCD_SPAWN, - PCD_SPAWNDIRECT, - PCD_SPAWNSPOT, - PCD_SPAWNSPOTDIRECT, - PCD_SETMUSIC, - PCD_SETMUSICDIRECT, - PCD_LOCALSETMUSIC, - PCD_LOCALSETMUSICDIRECT, - PCD_PRINTFIXED, - PCD_PRINTLOCALIZED, - PCD_MOREHUDMESSAGE, - PCD_OPTHUDMESSAGE, - PCD_ENDHUDMESSAGE, - PCD_ENDHUDMESSAGEBOLD, - PCD_SETSTYLE, - PCD_SETSTYLEDIRECT, - PCD_SETFONT, - PCD_SETFONTDIRECT, - PCD_PUSHBYTE, // Valid in compact-script mode only - PCD_LSPEC1DIRECTB, // " - PCD_LSPEC2DIRECTB, // " - PCD_LSPEC3DIRECTB, // " - PCD_LSPEC4DIRECTB, // " - PCD_LSPEC5DIRECTB, // " - PCD_DELAYDIRECTB, // " - PCD_RANDOMDIRECTB, // " - PCD_PUSHBYTES, // " - PCD_PUSH2BYTES, // " - PCD_PUSH3BYTES, // " - PCD_PUSH4BYTES, // " - PCD_PUSH5BYTES, // " - PCD_SETTHINGSPECIAL, - PCD_ASSIGNGLOBALVAR, - PCD_PUSHGLOBALVAR, - PCD_ADDGLOBALVAR, - PCD_SUBGLOBALVAR, - PCD_MULGLOBALVAR, - PCD_DIVGLOBALVAR, - PCD_MODGLOBALVAR, - PCD_INCGLOBALVAR, - PCD_DECGLOBALVAR, - PCD_FADETO, - PCD_FADERANGE, - PCD_CANCELFADE, - PCD_PLAYMOVIE, - PCD_SETFLOORTRIGGER, - PCD_SETCEILINGTRIGGER, - PCD_GETACTORX, - PCD_GETACTORY, - PCD_GETACTORZ, - PCD_STARTTRANSLATION, - PCD_TRANSLATIONRANGE1, - PCD_TRANSLATIONRANGE2, - PCD_ENDTRANSLATION, - PCD_CALL, - PCD_CALLDISCARD, - PCD_RETURNVOID, - PCD_RETURNVAL, - PCD_PUSHMAPARRAY, - PCD_ASSIGNMAPARRAY, - PCD_ADDMAPARRAY, - PCD_SUBMAPARRAY, - PCD_MULMAPARRAY, - PCD_DIVMAPARRAY, - PCD_MODMAPARRAY, - PCD_INCMAPARRAY, - PCD_DECMAPARRAY, - PCD_DUP, - PCD_SWAP, - PCD_WRITETOINI, - PCD_GETFROMINI, - PCD_SIN, - PCD_COS, - PCD_VECTORANGLE, - PCD_CHECKWEAPON, - PCD_SETWEAPON, - PCD_TAGSTRING, - PCD_PUSHWORLDARRAY, - PCD_ASSIGNWORLDARRAY, - PCD_ADDWORLDARRAY, - PCD_SUBWORLDARRAY, - PCD_MULWORLDARRAY, - PCD_DIVWORLDARRAY, - PCD_MODWORLDARRAY, - PCD_INCWORLDARRAY, - PCD_DECWORLDARRAY, - PCD_PUSHGLOBALARRAY, - PCD_ASSIGNGLOBALARRAY, - PCD_ADDGLOBALARRAY, - PCD_SUBGLOBALARRAY, - PCD_MULGLOBALARRAY, - PCD_DIVGLOBALARRAY, - PCD_MODGLOBALARRAY, - PCD_INCGLOBALARRAY, - PCD_DECGLOBALARRAY, - PCD_SETMARINEWEAPON, - PCD_SETACTORPROPERTY, - PCD_GETACTORPROPERTY, - PCD_PLAYERNUMBER, - PCD_ACTIVATORTID, - PCD_SETMARINESPRITE, - PCD_GETSCREENWIDTH, - PCD_GETSCREENHEIGHT, - PCD_THING_PROJECTILE2, - PCD_STRLEN, - PCD_SETHUDSIZE, - PCD_GETCVAR, - PCD_CASEGOTOSORTED, - PCD_SETRESULTVALUE, - PCD_GETLINEROWOFFSET, - PCD_GETACTORFLOORZ, - PCD_GETACTORANGLE, - PCD_GETSECTORFLOORZ, - PCD_GETSECTORCEILINGZ, - PCD_LSPEC5RESULT, - PCD_GETSIGILPIECES, - PCD_GETLEVELINFO, - PCD_CHANGESKY, - PCD_PLAYERINGAME, - PCD_PLAYERISBOT, - PCD_SETCAMERATOTEXTURE, - PCD_ENDLOG, - PCD_GETAMMOCAPACITY, - PCD_SETAMMOCAPACITY, -// [JB] start of new pcodes - PCD_PRINTMAPCHARARRAY, - PCD_PRINTWORLDCHARARRAY, - PCD_PRINTGLOBALCHARARRAY, -// [JB] end of new pcodes - PCD_SETACTORANGLE, - PCD_GRABINPUT, - PCD_SETMOUSEPOINTER, - PCD_MOVEMOUSEPOINTER, - PCD_SPAWNPROJECTILE, - PCD_GETSECTORLIGHTLEVEL, - PCD_GETACTORCEILINGZ, - PCD_SETACTORPOSITION, - PCD_CLEARACTORINVENTORY, - PCD_GIVEACTORINVENTORY, - PCD_TAKEACTORINVENTORY, - PCD_CHECKACTORINVENTORY, - PCD_THINGCOUNTNAME, - PCD_SPAWNSPOTFACING, - PCD_PLAYERCLASS, - //[MW] start my p-codes - PCD_ANDSCRIPTVAR, - PCD_ANDMAPVAR, - PCD_ANDWORLDVAR, - PCD_ANDGLOBALVAR, - PCD_ANDMAPARRAY, - PCD_ANDWORLDARRAY, - PCD_ANDGLOBALARRAY, - PCD_EORSCRIPTVAR, - PCD_EORMAPVAR, - PCD_EORWORLDVAR, - PCD_EORGLOBALVAR, - PCD_EORMAPARRAY, - PCD_EORWORLDARRAY, - PCD_EORGLOBALARRAY, - PCD_ORSCRIPTVAR, - PCD_ORMAPVAR, - PCD_ORWORLDVAR, - PCD_ORGLOBALVAR, - PCD_ORMAPARRAY, - PCD_ORWORLDARRAY, - PCD_ORGLOBALARRAY, - PCD_LSSCRIPTVAR, - PCD_LSMAPVAR, - PCD_LSWORLDVAR, - PCD_LSGLOBALVAR, - PCD_LSMAPARRAY, - PCD_LSWORLDARRAY, - PCD_LSGLOBALARRAY, - PCD_RSSCRIPTVAR, - PCD_RSMAPVAR, - PCD_RSWORLDVAR, - PCD_RSGLOBALVAR, - PCD_RSMAPARRAY, - PCD_RSWORLDARRAY, - PCD_RSGLOBALARRAY, - //[MW] end my p-codes - PCD_GETPLAYERINFO, - PCD_CHANGELEVEL, - PCD_SECTORDAMAGE, - PCD_REPLACETEXTURES, - PCD_NEGATEBINARY, - PCD_GETACTORPITCH, - PCD_SETACTORPITCH, - PCD_PRINTBIND, - PCD_SETACTORSTATE, - PCD_THINGDAMAGE2, - PCD_USEINVENTORY, - PCD_USEACTORINVENTORY, - PCD_CHECKACTORCEILINGTEXTURE, - PCD_CHECKACTORFLOORTEXTURE, - PCD_GETACTORLIGHTLEVEL, - PCD_SETMUGSHOTSTATE, - PCD_THINGCOUNTSECTOR, - PCD_THINGCOUNTNAMESECTOR, - PCD_CHECKPLAYERCAMERA, - PCD_MORPHACTOR, - PCD_UNMORPHACTOR, - PCD_GETPLAYERINPUT, - PCD_CLASSIFYACTOR, - PCD_PRINTBINARY, - PCD_PRINTHEX, - PCD_CALLFUNC, - PCD_SAVESTRING, // [FDARI] - PCD_PRINTMAPCHRANGE, // [FDARI] output range - PCD_PRINTWORLDCHRANGE, - PCD_PRINTGLOBALCHRANGE, - PCD_STRCPYTOMAPCHRANGE, // [FDARI] input range - PCD_STRCPYTOWORLDCHRANGE, - PCD_STRCPYTOGLOBALCHRANGE, - PCD_PUSHFUNCTION, // from Eternity - PCD_CALLSTACK, // from Eternity - PCD_SCRIPTWAITNAMED, - PCD_TRANSLATIONRANGE3, - PCD_GOTOSTACK, - PCD_ASSIGNSCRIPTARRAY, - PCD_PUSHSCRIPTARRAY, - PCD_ADDSCRIPTARRAY, - PCD_SUBSCRIPTARRAY, - PCD_MULSCRIPTARRAY, - PCD_DIVSCRIPTARRAY, - PCD_MODSCRIPTARRAY, - PCD_INCSCRIPTARRAY, - PCD_DECSCRIPTARRAY, - PCD_ANDSCRIPTARRAY, - PCD_EORSCRIPTARRAY, - PCD_ORSCRIPTARRAY, - PCD_LSSCRIPTARRAY, - PCD_RSSCRIPTARRAY, - PCD_PRINTSCRIPTCHARARRAY, - PCD_PRINTSCRIPTCHRANGE, - PCD_STRCPYTOSCRIPTCHRANGE, - PCD_LSPEC5EX, - PCD_LSPEC5EXRESULT, - PCD_TRANSLATIONRANGE4, - PCD_TRANSLATIONRANGE5, - - PCODE_COMMAND_COUNT -} pcd_t; - -// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- - -void PC_OpenObject(char *name, size_t size, int flags); -void PC_CloseObject(void); -void PC_Append(void *buffer, size_t size); -void PC_AppendByte(U_BYTE val); -void PC_AppendWord(U_WORD val); -void PC_AppendInt(U_INT val); -void PC_AppendString(char *string); -void PC_AppendCmd(pcd_t command); -void PC_AppendPushVal(U_INT val); -void PC_AppendShrink(U_BYTE val); -void PC_Write(void *buffer, size_t size, int address); -void PC_WriteByte(U_BYTE val, int address); -//void PC_WriteWord(U_WORD val, int address); -void PC_WriteInt(U_INT val, int address); -void PC_WriteString(char *string, int address); -void PC_WriteCmd(pcd_t command, int address); -void PC_Skip(size_t size); -//void PC_SkipByte(void); -//void PC_SkipWord(void); -void PC_SkipInt(void); -void PC_AddScript(int number, int type, int flags, int argCount); -void PC_SetScriptVarCount(int number, int type, int varCount, int arrayCount, int *arraySizes); -void PC_AddFunction(struct symbolNode_s *sym, int arrayCount, int *sizes); -void PC_PutMapVariable(int index, int value); -void PC_NameMapVariable(int index, struct symbolNode_s *sym); -void PC_AddArray(int index, int size); -void PC_InitArray(int index, int *entries, boolean hasStrings); -int PC_AddImport(char *name); - -// PUBLIC DATA DECLARATIONS ------------------------------------------------ - -extern int pc_Address; -extern byte *pc_Buffer; -extern byte *pc_BufferPtr; -extern int pc_ScriptCount; -extern int pc_FunctionCount; -extern boolean pc_NoShrink; -extern boolean pc_HexenCase; -extern boolean pc_EnforceHexen; -extern boolean pc_WarnNotHexen; -extern boolean pc_WadAuthor; -extern boolean pc_EncryptStrings; -extern int pc_LastAppendedCommand; - -#endif + +//************************************************************************** +//** +//** pcode.h +//** +//************************************************************************** + +#ifndef __PCODE_H__ +#define __PCODE_H__ + +// HEADER FILES ------------------------------------------------------------ + +#include +#include "common.h" + +// MACROS ------------------------------------------------------------------ + +// Values to indicate a script's type +enum +{ + OPEN_SCRIPTS_BASE = 1, + RESPAWN_SCRIPTS_BASE = 2, // [BC] + DEATH_SCRIPTS_BASE = 3, // [BC] + ENTER_SCRIPTS_BASE = 4, // [BC] + PICKUP_SCRIPTS_BASE = 5, // [BC] + BLUE_RETURN_SCRIPTS_BASE = 6, // [BC] + RED_RETURN_SCRIPTS_BASE = 7, // [BC] + WHITE_RETURN_SCRIPTS_BASE = 8, // [BC] + LIGHTNING_SCRIPTS_BASE = 12, + UNLOADING_SCRIPTS_BASE = 13, + DISCONNECT_SCRIPTS_BASE = 14, + RETURN_SCRIPTS_BASE = 15, + EVENT_SCRIPTS_BASE = 16, // [BB] + KILL_SCRIPTS_BASE = 17, // [JM] + REOPEN_SCRIPTS_BASE = 18, // [Nash] +}; + +// Values to indicate script flags (requires new-style .o) +enum +{ + NET_SCRIPT_FLAG = 0x0001, + CLIENTSIDE_SCRIPT_FLAG = 0x0002, // [BB] +}; + +// Or'ed with variable index when passing variables of type "out" +// An idea that was never realized. +enum +{ + OUTVAR_SCRIPT_SPEC = 0x40000000, + OUTVAR_MAP_SPEC = 0x80000000, + OUTVAR_WORLD_SPEC = 0xc0000000, + OUTVAR_GLOBAL_SPEC = 0x00000000 +}; + +// TYPES ------------------------------------------------------------------- + +struct symbolNode_s; // Defined in symbol.h + +typedef enum +{ + PCD_NOP, + PCD_TERMINATE, + PCD_SUSPEND, + PCD_PUSHNUMBER, + PCD_LSPEC1, + PCD_LSPEC2, + PCD_LSPEC3, + PCD_LSPEC4, + PCD_LSPEC5, + PCD_LSPEC1DIRECT, + PCD_LSPEC2DIRECT, + PCD_LSPEC3DIRECT, + PCD_LSPEC4DIRECT, + PCD_LSPEC5DIRECT, + PCD_ADD, + PCD_SUBTRACT, + PCD_MULTIPLY, + PCD_DIVIDE, + PCD_MODULUS, + PCD_EQ, + PCD_NE, + PCD_LT, + PCD_GT, + PCD_LE, + PCD_GE, + PCD_ASSIGNSCRIPTVAR, + PCD_ASSIGNMAPVAR, + PCD_ASSIGNWORLDVAR, + PCD_PUSHSCRIPTVAR, + PCD_PUSHMAPVAR, + PCD_PUSHWORLDVAR, + PCD_ADDSCRIPTVAR, + PCD_ADDMAPVAR, + PCD_ADDWORLDVAR, + PCD_SUBSCRIPTVAR, + PCD_SUBMAPVAR, + PCD_SUBWORLDVAR, + PCD_MULSCRIPTVAR, + PCD_MULMAPVAR, + PCD_MULWORLDVAR, + PCD_DIVSCRIPTVAR, + PCD_DIVMAPVAR, + PCD_DIVWORLDVAR, + PCD_MODSCRIPTVAR, + PCD_MODMAPVAR, + PCD_MODWORLDVAR, + PCD_INCSCRIPTVAR, + PCD_INCMAPVAR, + PCD_INCWORLDVAR, + PCD_DECSCRIPTVAR, + PCD_DECMAPVAR, + PCD_DECWORLDVAR, + PCD_GOTO, + PCD_IFGOTO, + PCD_DROP, + PCD_DELAY, + PCD_DELAYDIRECT, + PCD_RANDOM, + PCD_RANDOMDIRECT, + PCD_THINGCOUNT, + PCD_THINGCOUNTDIRECT, + PCD_TAGWAIT, + PCD_TAGWAITDIRECT, + PCD_POLYWAIT, + PCD_POLYWAITDIRECT, + PCD_CHANGEFLOOR, + PCD_CHANGEFLOORDIRECT, + PCD_CHANGECEILING, + PCD_CHANGECEILINGDIRECT, + PCD_RESTART, + PCD_ANDLOGICAL, + PCD_ORLOGICAL, + PCD_ANDBITWISE, + PCD_ORBITWISE, + PCD_EORBITWISE, + PCD_NEGATELOGICAL, + PCD_LSHIFT, + PCD_RSHIFT, + PCD_UNARYMINUS, + PCD_IFNOTGOTO, + PCD_LINESIDE, + PCD_SCRIPTWAIT, + PCD_SCRIPTWAITDIRECT, + PCD_CLEARLINESPECIAL, + PCD_CASEGOTO, + PCD_BEGINPRINT, + PCD_ENDPRINT, + PCD_PRINTSTRING, + PCD_PRINTNUMBER, + PCD_PRINTCHARACTER, + PCD_PLAYERCOUNT, + PCD_GAMETYPE, + PCD_GAMESKILL, + PCD_TIMER, + PCD_SECTORSOUND, + PCD_AMBIENTSOUND, + PCD_SOUNDSEQUENCE, + PCD_SETLINETEXTURE, + PCD_SETLINEBLOCKING, + PCD_SETLINESPECIAL, + PCD_THINGSOUND, + PCD_ENDPRINTBOLD, +// [RH] End of Hexen p-codes + PCD_ACTIVATORSOUND, + PCD_LOCALAMBIENTSOUND, + PCD_SETLINEMONSTERBLOCKING, +// [BC] Start of new pcodes + PCD_PLAYERBLUESKULL, + PCD_PLAYERREDSKULL, + PCD_PLAYERYELLOWSKULL, + PCD_PLAYERMASTERSKULL, + PCD_PLAYERBLUECARD, + PCD_PLAYERREDCARD, + PCD_PLAYERYELLOWCARD, + PCD_PLAYERMASTERCARD, + PCD_PLAYERBLACKSKULL, + PCD_PLAYERSILVERSKULL, + PCD_PLAYERGOLDSKULL, + PCD_PLAYERBLACKCARD, + PCD_PLAYERSILVERCARD, + PCD_ISNETWORKGAME, + PCD_PLAYERTEAM, + PCD_PLAYERHEALTH, + PCD_PLAYERARMORPOINTS, + PCD_PLAYERFRAGS, + PCD_PLAYEREXPERT, + PCD_BLUETEAMCOUNT, + PCD_REDTEAMCOUNT, + PCD_BLUETEAMSCORE, + PCD_REDTEAMSCORE, + PCD_ISONEFLAGCTF, + PCD_GETINVASIONWAVE, + PCD_GETINVASIONSTATE, + PCD_PRINTNAME, + PCD_MUSICCHANGE, + PCD_CONSOLECOMMANDDIRECT, + PCD_CONSOLECOMMAND, + PCD_SINGLEPLAYER, +// [RH] End of Skull Tag p-codes + PCD_FIXEDMUL, + PCD_FIXEDDIV, + PCD_SETGRAVITY, + PCD_SETGRAVITYDIRECT, + PCD_SETAIRCONTROL, + PCD_SETAIRCONTROLDIRECT, + PCD_CLEARINVENTORY, + PCD_GIVEINVENTORY, + PCD_GIVEINVENTORYDIRECT, + PCD_TAKEINVENTORY, + PCD_TAKEINVENTORYDIRECT, + PCD_CHECKINVENTORY, + PCD_CHECKINVENTORYDIRECT, + PCD_SPAWN, + PCD_SPAWNDIRECT, + PCD_SPAWNSPOT, + PCD_SPAWNSPOTDIRECT, + PCD_SETMUSIC, + PCD_SETMUSICDIRECT, + PCD_LOCALSETMUSIC, + PCD_LOCALSETMUSICDIRECT, + PCD_PRINTFIXED, + PCD_PRINTLOCALIZED, + PCD_MOREHUDMESSAGE, + PCD_OPTHUDMESSAGE, + PCD_ENDHUDMESSAGE, + PCD_ENDHUDMESSAGEBOLD, + PCD_SETSTYLE, + PCD_SETSTYLEDIRECT, + PCD_SETFONT, + PCD_SETFONTDIRECT, + PCD_PUSHBYTE, // Valid in compact-script mode only + PCD_LSPEC1DIRECTB, // " + PCD_LSPEC2DIRECTB, // " + PCD_LSPEC3DIRECTB, // " + PCD_LSPEC4DIRECTB, // " + PCD_LSPEC5DIRECTB, // " + PCD_DELAYDIRECTB, // " + PCD_RANDOMDIRECTB, // " + PCD_PUSHBYTES, // " + PCD_PUSH2BYTES, // " + PCD_PUSH3BYTES, // " + PCD_PUSH4BYTES, // " + PCD_PUSH5BYTES, // " + PCD_SETTHINGSPECIAL, + PCD_ASSIGNGLOBALVAR, + PCD_PUSHGLOBALVAR, + PCD_ADDGLOBALVAR, + PCD_SUBGLOBALVAR, + PCD_MULGLOBALVAR, + PCD_DIVGLOBALVAR, + PCD_MODGLOBALVAR, + PCD_INCGLOBALVAR, + PCD_DECGLOBALVAR, + PCD_FADETO, + PCD_FADERANGE, + PCD_CANCELFADE, + PCD_PLAYMOVIE, + PCD_SETFLOORTRIGGER, + PCD_SETCEILINGTRIGGER, + PCD_GETACTORX, + PCD_GETACTORY, + PCD_GETACTORZ, + PCD_STARTTRANSLATION, + PCD_TRANSLATIONRANGE1, + PCD_TRANSLATIONRANGE2, + PCD_ENDTRANSLATION, + PCD_CALL, + PCD_CALLDISCARD, + PCD_RETURNVOID, + PCD_RETURNVAL, + PCD_PUSHMAPARRAY, + PCD_ASSIGNMAPARRAY, + PCD_ADDMAPARRAY, + PCD_SUBMAPARRAY, + PCD_MULMAPARRAY, + PCD_DIVMAPARRAY, + PCD_MODMAPARRAY, + PCD_INCMAPARRAY, + PCD_DECMAPARRAY, + PCD_DUP, + PCD_SWAP, + PCD_WRITETOINI, + PCD_GETFROMINI, + PCD_SIN, + PCD_COS, + PCD_VECTORANGLE, + PCD_CHECKWEAPON, + PCD_SETWEAPON, + PCD_TAGSTRING, + PCD_PUSHWORLDARRAY, + PCD_ASSIGNWORLDARRAY, + PCD_ADDWORLDARRAY, + PCD_SUBWORLDARRAY, + PCD_MULWORLDARRAY, + PCD_DIVWORLDARRAY, + PCD_MODWORLDARRAY, + PCD_INCWORLDARRAY, + PCD_DECWORLDARRAY, + PCD_PUSHGLOBALARRAY, + PCD_ASSIGNGLOBALARRAY, + PCD_ADDGLOBALARRAY, + PCD_SUBGLOBALARRAY, + PCD_MULGLOBALARRAY, + PCD_DIVGLOBALARRAY, + PCD_MODGLOBALARRAY, + PCD_INCGLOBALARRAY, + PCD_DECGLOBALARRAY, + PCD_SETMARINEWEAPON, + PCD_SETACTORPROPERTY, + PCD_GETACTORPROPERTY, + PCD_PLAYERNUMBER, + PCD_ACTIVATORTID, + PCD_SETMARINESPRITE, + PCD_GETSCREENWIDTH, + PCD_GETSCREENHEIGHT, + PCD_THING_PROJECTILE2, + PCD_STRLEN, + PCD_SETHUDSIZE, + PCD_GETCVAR, + PCD_CASEGOTOSORTED, + PCD_SETRESULTVALUE, + PCD_GETLINEROWOFFSET, + PCD_GETACTORFLOORZ, + PCD_GETACTORANGLE, + PCD_GETSECTORFLOORZ, + PCD_GETSECTORCEILINGZ, + PCD_LSPEC5RESULT, + PCD_GETSIGILPIECES, + PCD_GETLEVELINFO, + PCD_CHANGESKY, + PCD_PLAYERINGAME, + PCD_PLAYERISBOT, + PCD_SETCAMERATOTEXTURE, + PCD_ENDLOG, + PCD_GETAMMOCAPACITY, + PCD_SETAMMOCAPACITY, +// [JB] start of new pcodes + PCD_PRINTMAPCHARARRAY, + PCD_PRINTWORLDCHARARRAY, + PCD_PRINTGLOBALCHARARRAY, +// [JB] end of new pcodes + PCD_SETACTORANGLE, + PCD_GRABINPUT, + PCD_SETMOUSEPOINTER, + PCD_MOVEMOUSEPOINTER, + PCD_SPAWNPROJECTILE, + PCD_GETSECTORLIGHTLEVEL, + PCD_GETACTORCEILINGZ, + PCD_SETACTORPOSITION, + PCD_CLEARACTORINVENTORY, + PCD_GIVEACTORINVENTORY, + PCD_TAKEACTORINVENTORY, + PCD_CHECKACTORINVENTORY, + PCD_THINGCOUNTNAME, + PCD_SPAWNSPOTFACING, + PCD_PLAYERCLASS, + //[MW] start my p-codes + PCD_ANDSCRIPTVAR, + PCD_ANDMAPVAR, + PCD_ANDWORLDVAR, + PCD_ANDGLOBALVAR, + PCD_ANDMAPARRAY, + PCD_ANDWORLDARRAY, + PCD_ANDGLOBALARRAY, + PCD_EORSCRIPTVAR, + PCD_EORMAPVAR, + PCD_EORWORLDVAR, + PCD_EORGLOBALVAR, + PCD_EORMAPARRAY, + PCD_EORWORLDARRAY, + PCD_EORGLOBALARRAY, + PCD_ORSCRIPTVAR, + PCD_ORMAPVAR, + PCD_ORWORLDVAR, + PCD_ORGLOBALVAR, + PCD_ORMAPARRAY, + PCD_ORWORLDARRAY, + PCD_ORGLOBALARRAY, + PCD_LSSCRIPTVAR, + PCD_LSMAPVAR, + PCD_LSWORLDVAR, + PCD_LSGLOBALVAR, + PCD_LSMAPARRAY, + PCD_LSWORLDARRAY, + PCD_LSGLOBALARRAY, + PCD_RSSCRIPTVAR, + PCD_RSMAPVAR, + PCD_RSWORLDVAR, + PCD_RSGLOBALVAR, + PCD_RSMAPARRAY, + PCD_RSWORLDARRAY, + PCD_RSGLOBALARRAY, + //[MW] end my p-codes + PCD_GETPLAYERINFO, + PCD_CHANGELEVEL, + PCD_SECTORDAMAGE, + PCD_REPLACETEXTURES, + PCD_NEGATEBINARY, + PCD_GETACTORPITCH, + PCD_SETACTORPITCH, + PCD_PRINTBIND, + PCD_SETACTORSTATE, + PCD_THINGDAMAGE2, + PCD_USEINVENTORY, + PCD_USEACTORINVENTORY, + PCD_CHECKACTORCEILINGTEXTURE, + PCD_CHECKACTORFLOORTEXTURE, + PCD_GETACTORLIGHTLEVEL, + PCD_SETMUGSHOTSTATE, + PCD_THINGCOUNTSECTOR, + PCD_THINGCOUNTNAMESECTOR, + PCD_CHECKPLAYERCAMERA, + PCD_MORPHACTOR, + PCD_UNMORPHACTOR, + PCD_GETPLAYERINPUT, + PCD_CLASSIFYACTOR, + PCD_PRINTBINARY, + PCD_PRINTHEX, + PCD_CALLFUNC, + PCD_SAVESTRING, // [FDARI] + PCD_PRINTMAPCHRANGE, // [FDARI] output range + PCD_PRINTWORLDCHRANGE, + PCD_PRINTGLOBALCHRANGE, + PCD_STRCPYTOMAPCHRANGE, // [FDARI] input range + PCD_STRCPYTOWORLDCHRANGE, + PCD_STRCPYTOGLOBALCHRANGE, + PCD_PUSHFUNCTION, // from Eternity + PCD_CALLSTACK, // from Eternity + PCD_SCRIPTWAITNAMED, + PCD_TRANSLATIONRANGE3, + PCD_GOTOSTACK, + PCD_ASSIGNSCRIPTARRAY, + PCD_PUSHSCRIPTARRAY, + PCD_ADDSCRIPTARRAY, + PCD_SUBSCRIPTARRAY, + PCD_MULSCRIPTARRAY, + PCD_DIVSCRIPTARRAY, + PCD_MODSCRIPTARRAY, + PCD_INCSCRIPTARRAY, + PCD_DECSCRIPTARRAY, + PCD_ANDSCRIPTARRAY, + PCD_EORSCRIPTARRAY, + PCD_ORSCRIPTARRAY, + PCD_LSSCRIPTARRAY, + PCD_RSSCRIPTARRAY, + PCD_PRINTSCRIPTCHARARRAY, + PCD_PRINTSCRIPTCHRANGE, + PCD_STRCPYTOSCRIPTCHRANGE, + PCD_LSPEC5EX, + PCD_LSPEC5EXRESULT, + PCD_TRANSLATIONRANGE4, + PCD_TRANSLATIONRANGE5, + + PCODE_COMMAND_COUNT +} pcd_t; + +// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- + +void PC_OpenObject(char *name, size_t size, int flags); +void PC_CloseObject(void); +void PC_Append(void *buffer, size_t size); +void PC_AppendByte(U_BYTE val); +void PC_AppendWord(U_WORD val); +void PC_AppendInt(U_INT val); +void PC_AppendString(char *string); +void PC_AppendCmd(pcd_t command); +void PC_AppendPushVal(U_INT val); +void PC_AppendShrink(U_BYTE val); +void PC_Write(void *buffer, size_t size, int address); +void PC_WriteByte(U_BYTE val, int address); +//void PC_WriteWord(U_WORD val, int address); +void PC_WriteInt(U_INT val, int address); +void PC_WriteString(char *string, int address); +void PC_WriteCmd(pcd_t command, int address); +void PC_Skip(size_t size); +//void PC_SkipByte(void); +//void PC_SkipWord(void); +void PC_SkipInt(void); +void PC_AddScript(int number, int type, int flags, int argCount); +void PC_SetScriptVarCount(int number, int type, int varCount, int arrayCount, int *arraySizes); +void PC_AddFunction(struct symbolNode_s *sym, int arrayCount, int *sizes); +void PC_PutMapVariable(int index, int value); +void PC_NameMapVariable(int index, struct symbolNode_s *sym); +void PC_AddArray(int index, int size); +void PC_InitArray(int index, int *entries, boolean hasStrings); +int PC_AddImport(char *name); + +// PUBLIC DATA DECLARATIONS ------------------------------------------------ + +extern int pc_Address; +extern byte *pc_Buffer; +extern byte *pc_BufferPtr; +extern int pc_ScriptCount; +extern int pc_FunctionCount; +extern boolean pc_NoShrink; +extern boolean pc_HexenCase; +extern boolean pc_EnforceHexen; +extern boolean pc_WarnNotHexen; +extern boolean pc_WadAuthor; +extern boolean pc_EncryptStrings; +extern int pc_LastAppendedCommand; + +#endif diff --git a/strlist.c b/strlist.c index daec46c..ab96d45 100644 --- a/strlist.c +++ b/strlist.c @@ -1,426 +1,426 @@ - -//************************************************************************** -//** -//** strlist.c -//** -//************************************************************************** - -// HEADER FILES ------------------------------------------------------------ - -#include -#include -#include "common.h" -#include "strlist.h" -#include "error.h" -#include "misc.h" -#include "pcode.h" - -// MACROS ------------------------------------------------------------------ - -// TYPES ------------------------------------------------------------------- - -typedef struct -{ - char *name; - int address; -} stringInfo_t; - -typedef struct -{ - int stringCount; - stringInfo_t strings[MAX_STRINGS]; -} stringList_t; - -// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- - -// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- - -// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- - -static int STR_PutStringInSomeList(stringList_t *list, int index, char *name); -static int STR_FindInSomeList(stringList_t *list, char *name); -static int STR_FindInSomeListInsensitive(stringList_t *list, char *name); -static void DumpStrings(stringList_t *list, int lenadr, boolean quad, boolean crypt); -static void Encrypt(void *data, int key, int len); - -// EXTERNAL DATA DECLARATIONS ---------------------------------------------- - -// PUBLIC DATA DEFINITIONS ------------------------------------------------- - -int NumLanguages, NumStringLists; - -// PRIVATE DATA DEFINITIONS ------------------------------------------------ - -static stringList_t MainStringList; -static stringList_t *StringLists[NUM_STRLISTS]; - -// CODE -------------------------------------------------------------------- - -//========================================================================== -// -// STR_Init -// -//========================================================================== - -void STR_Init(void) -{ - NumStringLists = 0; - MainStringList.stringCount = 0; -} - -//========================================================================== -// -// STR_Get -// -//========================================================================== - -char *STR_Get(int num) -{ - return MainStringList.strings[num].name; -} - -//========================================================================== -// -// STR_Find -// -//========================================================================== - -int STR_Find(char *name) -{ - return STR_FindInSomeList(&MainStringList, name); -} - -//========================================================================== -// -// STR_FindInList -// -//========================================================================== - -int STR_FindInList(int list, char *name) -{ - if (StringLists[list] == NULL) - { - StringLists[list] = MS_Alloc(sizeof(stringList_t), ERR_OUT_OF_MEMORY); - StringLists[list]->stringCount = 0; - NumStringLists++; - if(pc_EnforceHexen) - { - ERR_Error(ERR_HEXEN_COMPAT, YES); - } - } - return STR_FindInSomeList (StringLists[list], name); -} - -//========================================================================== -// -// STR_FindInSomeList -// -//========================================================================== - -static int STR_FindInSomeList(stringList_t *list, char *name) -{ - int i; - - for(i = 0; i < list->stringCount; i++) - { - if(strcmp(list->strings[i].name, name) == 0) - { - return i; - } - } - // Add to list - return STR_PutStringInSomeList(list, i, name); -} - -//========================================================================== -// -// STR_FindInListInsensitive -// -//========================================================================== - -int STR_FindInListInsensitive(int list, char *name) -{ - if (StringLists[list] == NULL) - { - StringLists[list] = MS_Alloc(sizeof(stringList_t), ERR_OUT_OF_MEMORY); - StringLists[list]->stringCount = 0; - NumStringLists++; - if(pc_EnforceHexen) - { - ERR_Error(ERR_HEXEN_COMPAT, YES); - } - } - return STR_FindInSomeListInsensitive (StringLists[list], name); -} - -//========================================================================== -// -// STR_FindInSomeListInsensitive -// -//========================================================================== - -static int STR_FindInSomeListInsensitive(stringList_t *list, char *name) -{ - int i; - - for(i = 0; i < list->stringCount; i++) - { - if(strcasecmp(list->strings[i].name, name) == 0) - { - return i; - } - } - // Add to list - return STR_PutStringInSomeList(list, i, name); -} - -//========================================================================== -// -// STR_GetString -// -//========================================================================== - -const char *STR_GetString(int list, int index) -{ - if (StringLists[list] == NULL) - { - return NULL; - } - if (index < 0 || index >= StringLists[list]->stringCount) - { - return NULL; - } - return StringLists[list]->strings[index].name; -} - -//========================================================================== -// -// STR_AppendToList -// -//========================================================================== - -int STR_AppendToList(int list, char *name) -{ - if (StringLists[list] == NULL) - { - StringLists[list] = MS_Alloc(sizeof(stringList_t), ERR_OUT_OF_MEMORY); - StringLists[list]->stringCount = 0; - NumStringLists++; - } - return STR_PutStringInSomeList(StringLists[list], StringLists[list]->stringCount, name); -} - -//========================================================================== -// -// STR_PutStringInSomeList -// -//========================================================================== - -static int STR_PutStringInSomeList(stringList_t *list, int index, char *name) -{ - int i; - - if(index >= MAX_STRINGS) - { - ERR_Error(ERR_TOO_MANY_STRINGS, YES, MAX_STRINGS); - return 0; - } - MS_Message(MSG_DEBUG, "Adding string %d:\n \"%s\"\n", - list->stringCount, name); - if(index >= list->stringCount) - { - for(i = list->stringCount; i <= index; i++) - { - list->strings[i].name = NULL; - } - list->stringCount = index + 1; - } - if(list->strings[index].name != NULL) - { - free(list->strings[index].name); - } - if(name != NULL) - { - list->strings[index].name = MS_Alloc(strlen(name)+1, ERR_OUT_OF_MEMORY); - strcpy(list->strings[index].name, name); - } - else - { - list->strings[index].name = NULL; - } - return index; -} - -//========================================================================== -// -// STR_ListSize -// -//========================================================================== - -int STR_ListSize() -{ - return MainStringList.stringCount; -} - -//========================================================================== -// -// STR_WriteStrings -// -// Writes all the strings to the p-code buffer. -// -//========================================================================== - -void STR_WriteStrings(void) -{ - int i; - U_INT pad; - - MS_Message(MSG_DEBUG, "---- STR_WriteStrings ----\n"); - for(i = 0; i < MainStringList.stringCount; i++) - { - MainStringList.strings[i].address = pc_Address; - PC_AppendString(MainStringList.strings[i].name); - } - if(pc_Address%4 != 0) - { // Need to align - pad = 0; - PC_Append((void *)&pad, 4-(pc_Address%4)); - } -} - -//========================================================================== -// -// STR_WriteList -// -//========================================================================== - -void STR_WriteList(void) -{ - int i; - - MS_Message(MSG_DEBUG, "---- STR_WriteList ----\n"); - PC_AppendInt((U_INT)MainStringList.stringCount); - for(i = 0; i < MainStringList.stringCount; i++) - { - PC_AppendInt((U_INT)MainStringList.strings[i].address); - } -} - -//========================================================================== -// -// STR_WriteChunk -// -//========================================================================== - -void STR_WriteChunk(boolean encrypt) -{ - int lenadr; - - MS_Message(MSG_DEBUG, "---- STR_WriteChunk ----\n"); - PC_Append(encrypt ? "STRE" : "STRL", 4); - lenadr = pc_Address; - PC_SkipInt(); - PC_AppendInt(0); - PC_AppendInt(MainStringList.stringCount); - PC_AppendInt(0); // Used in-game for stringing lists together (NOT!) - - DumpStrings (&MainStringList, lenadr, NO, encrypt); -} - -//========================================================================== -// -// STR_WriteListChunk -// -//========================================================================== - -void STR_WriteListChunk(int list, int id, boolean quad) -{ - int lenadr; - - if (StringLists[list] != NULL && StringLists[list]->stringCount > 0) - { - MS_Message(MSG_DEBUG, "---- STR_WriteListChunk %d %c%c%c%c----\n", list, - id&255, (id>>8)&255, (id>>16)&255, (id>>24)&255); - PC_AppendInt((U_INT)id); - lenadr = pc_Address; - PC_SkipInt(); - PC_AppendInt(StringLists[list]->stringCount); - if (quad && pc_Address%8 != 0) - { // If writing quadword indices, align the indices to an - // 8-byte boundary. - U_INT pad = 0; - PC_Append (&pad, 4); - } - DumpStrings(StringLists[list], lenadr, quad, NO); - } -} - -//========================================================================== -// -// DumpStrings -// -//========================================================================== - -static void DumpStrings(stringList_t *list, int lenadr, boolean quad, boolean crypt) -{ - int i, ofs, startofs; - - startofs = ofs = pc_Address - lenadr - 4 + list->stringCount*(quad?8:4); - - for(i = 0; i < list->stringCount; i++) - { - if (list->strings[i].name != NULL) - { - PC_AppendInt((U_INT)ofs); - ofs += strlen(list->strings[i].name) + 1; - } - else - { - PC_AppendInt(0); - } - if (quad) - { - PC_AppendInt(0); - } - } - - ofs = startofs; - - for(i = 0; i < list->stringCount; i++) - { - if(list->strings[i].name != NULL) - { - int stringlen = strlen(list->strings[i].name) + 1; - if(crypt) - { - int cryptkey = ofs*157135; - - Encrypt(list->strings[i].name, cryptkey, stringlen); - PC_Append(list->strings[i].name, stringlen); - ofs += stringlen; - Encrypt(list->strings[i].name, cryptkey, stringlen); - } - else - { - PC_AppendString(list->strings[i].name); - } - } - } - if(pc_Address%4 != 0) - { // Need to align - U_INT pad = 0; - PC_Append((void *)&pad, 4-(pc_Address%4)); - } - - PC_WriteInt(pc_Address - lenadr - 4, lenadr); -} - -static void Encrypt(void *data, int key, int len) -{ - int p = (byte)key, i; - - for(i = 0; i < len; ++i) - { - ((byte *)data)[i] ^= (byte)(p+(i>>1)); - } -} + +//************************************************************************** +//** +//** strlist.c +//** +//************************************************************************** + +// HEADER FILES ------------------------------------------------------------ + +#include +#include +#include "common.h" +#include "strlist.h" +#include "error.h" +#include "misc.h" +#include "pcode.h" + +// MACROS ------------------------------------------------------------------ + +// TYPES ------------------------------------------------------------------- + +typedef struct +{ + char *name; + int address; +} stringInfo_t; + +typedef struct +{ + int stringCount; + stringInfo_t strings[MAX_STRINGS]; +} stringList_t; + +// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- + +// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- + +// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- + +static int STR_PutStringInSomeList(stringList_t *list, int index, char *name); +static int STR_FindInSomeList(stringList_t *list, char *name); +static int STR_FindInSomeListInsensitive(stringList_t *list, char *name); +static void DumpStrings(stringList_t *list, int lenadr, boolean quad, boolean crypt); +static void Encrypt(void *data, int key, int len); + +// EXTERNAL DATA DECLARATIONS ---------------------------------------------- + +// PUBLIC DATA DEFINITIONS ------------------------------------------------- + +int NumLanguages, NumStringLists; + +// PRIVATE DATA DEFINITIONS ------------------------------------------------ + +static stringList_t MainStringList; +static stringList_t *StringLists[NUM_STRLISTS]; + +// CODE -------------------------------------------------------------------- + +//========================================================================== +// +// STR_Init +// +//========================================================================== + +void STR_Init(void) +{ + NumStringLists = 0; + MainStringList.stringCount = 0; +} + +//========================================================================== +// +// STR_Get +// +//========================================================================== + +char *STR_Get(int num) +{ + return MainStringList.strings[num].name; +} + +//========================================================================== +// +// STR_Find +// +//========================================================================== + +int STR_Find(char *name) +{ + return STR_FindInSomeList(&MainStringList, name); +} + +//========================================================================== +// +// STR_FindInList +// +//========================================================================== + +int STR_FindInList(int list, char *name) +{ + if (StringLists[list] == NULL) + { + StringLists[list] = MS_Alloc(sizeof(stringList_t), ERR_OUT_OF_MEMORY); + StringLists[list]->stringCount = 0; + NumStringLists++; + if(pc_EnforceHexen) + { + ERR_Error(ERR_HEXEN_COMPAT, YES); + } + } + return STR_FindInSomeList (StringLists[list], name); +} + +//========================================================================== +// +// STR_FindInSomeList +// +//========================================================================== + +static int STR_FindInSomeList(stringList_t *list, char *name) +{ + int i; + + for(i = 0; i < list->stringCount; i++) + { + if(strcmp(list->strings[i].name, name) == 0) + { + return i; + } + } + // Add to list + return STR_PutStringInSomeList(list, i, name); +} + +//========================================================================== +// +// STR_FindInListInsensitive +// +//========================================================================== + +int STR_FindInListInsensitive(int list, char *name) +{ + if (StringLists[list] == NULL) + { + StringLists[list] = MS_Alloc(sizeof(stringList_t), ERR_OUT_OF_MEMORY); + StringLists[list]->stringCount = 0; + NumStringLists++; + if(pc_EnforceHexen) + { + ERR_Error(ERR_HEXEN_COMPAT, YES); + } + } + return STR_FindInSomeListInsensitive (StringLists[list], name); +} + +//========================================================================== +// +// STR_FindInSomeListInsensitive +// +//========================================================================== + +static int STR_FindInSomeListInsensitive(stringList_t *list, char *name) +{ + int i; + + for(i = 0; i < list->stringCount; i++) + { + if(strcasecmp(list->strings[i].name, name) == 0) + { + return i; + } + } + // Add to list + return STR_PutStringInSomeList(list, i, name); +} + +//========================================================================== +// +// STR_GetString +// +//========================================================================== + +const char *STR_GetString(int list, int index) +{ + if (StringLists[list] == NULL) + { + return NULL; + } + if (index < 0 || index >= StringLists[list]->stringCount) + { + return NULL; + } + return StringLists[list]->strings[index].name; +} + +//========================================================================== +// +// STR_AppendToList +// +//========================================================================== + +int STR_AppendToList(int list, char *name) +{ + if (StringLists[list] == NULL) + { + StringLists[list] = MS_Alloc(sizeof(stringList_t), ERR_OUT_OF_MEMORY); + StringLists[list]->stringCount = 0; + NumStringLists++; + } + return STR_PutStringInSomeList(StringLists[list], StringLists[list]->stringCount, name); +} + +//========================================================================== +// +// STR_PutStringInSomeList +// +//========================================================================== + +static int STR_PutStringInSomeList(stringList_t *list, int index, char *name) +{ + int i; + + if(index >= MAX_STRINGS) + { + ERR_Error(ERR_TOO_MANY_STRINGS, YES, MAX_STRINGS); + return 0; + } + MS_Message(MSG_DEBUG, "Adding string %d:\n \"%s\"\n", + list->stringCount, name); + if(index >= list->stringCount) + { + for(i = list->stringCount; i <= index; i++) + { + list->strings[i].name = NULL; + } + list->stringCount = index + 1; + } + if(list->strings[index].name != NULL) + { + free(list->strings[index].name); + } + if(name != NULL) + { + list->strings[index].name = MS_Alloc(strlen(name)+1, ERR_OUT_OF_MEMORY); + strcpy(list->strings[index].name, name); + } + else + { + list->strings[index].name = NULL; + } + return index; +} + +//========================================================================== +// +// STR_ListSize +// +//========================================================================== + +int STR_ListSize() +{ + return MainStringList.stringCount; +} + +//========================================================================== +// +// STR_WriteStrings +// +// Writes all the strings to the p-code buffer. +// +//========================================================================== + +void STR_WriteStrings(void) +{ + int i; + U_INT pad; + + MS_Message(MSG_DEBUG, "---- STR_WriteStrings ----\n"); + for(i = 0; i < MainStringList.stringCount; i++) + { + MainStringList.strings[i].address = pc_Address; + PC_AppendString(MainStringList.strings[i].name); + } + if(pc_Address%4 != 0) + { // Need to align + pad = 0; + PC_Append((void *)&pad, 4-(pc_Address%4)); + } +} + +//========================================================================== +// +// STR_WriteList +// +//========================================================================== + +void STR_WriteList(void) +{ + int i; + + MS_Message(MSG_DEBUG, "---- STR_WriteList ----\n"); + PC_AppendInt((U_INT)MainStringList.stringCount); + for(i = 0; i < MainStringList.stringCount; i++) + { + PC_AppendInt((U_INT)MainStringList.strings[i].address); + } +} + +//========================================================================== +// +// STR_WriteChunk +// +//========================================================================== + +void STR_WriteChunk(boolean encrypt) +{ + int lenadr; + + MS_Message(MSG_DEBUG, "---- STR_WriteChunk ----\n"); + PC_Append(encrypt ? "STRE" : "STRL", 4); + lenadr = pc_Address; + PC_SkipInt(); + PC_AppendInt(0); + PC_AppendInt(MainStringList.stringCount); + PC_AppendInt(0); // Used in-game for stringing lists together (NOT!) + + DumpStrings (&MainStringList, lenadr, NO, encrypt); +} + +//========================================================================== +// +// STR_WriteListChunk +// +//========================================================================== + +void STR_WriteListChunk(int list, int id, boolean quad) +{ + int lenadr; + + if (StringLists[list] != NULL && StringLists[list]->stringCount > 0) + { + MS_Message(MSG_DEBUG, "---- STR_WriteListChunk %d %c%c%c%c----\n", list, + id&255, (id>>8)&255, (id>>16)&255, (id>>24)&255); + PC_AppendInt((U_INT)id); + lenadr = pc_Address; + PC_SkipInt(); + PC_AppendInt(StringLists[list]->stringCount); + if (quad && pc_Address%8 != 0) + { // If writing quadword indices, align the indices to an + // 8-byte boundary. + U_INT pad = 0; + PC_Append (&pad, 4); + } + DumpStrings(StringLists[list], lenadr, quad, NO); + } +} + +//========================================================================== +// +// DumpStrings +// +//========================================================================== + +static void DumpStrings(stringList_t *list, int lenadr, boolean quad, boolean crypt) +{ + int i, ofs, startofs; + + startofs = ofs = pc_Address - lenadr - 4 + list->stringCount*(quad?8:4); + + for(i = 0; i < list->stringCount; i++) + { + if (list->strings[i].name != NULL) + { + PC_AppendInt((U_INT)ofs); + ofs += strlen(list->strings[i].name) + 1; + } + else + { + PC_AppendInt(0); + } + if (quad) + { + PC_AppendInt(0); + } + } + + ofs = startofs; + + for(i = 0; i < list->stringCount; i++) + { + if(list->strings[i].name != NULL) + { + int stringlen = strlen(list->strings[i].name) + 1; + if(crypt) + { + int cryptkey = ofs*157135; + + Encrypt(list->strings[i].name, cryptkey, stringlen); + PC_Append(list->strings[i].name, stringlen); + ofs += stringlen; + Encrypt(list->strings[i].name, cryptkey, stringlen); + } + else + { + PC_AppendString(list->strings[i].name); + } + } + } + if(pc_Address%4 != 0) + { // Need to align + U_INT pad = 0; + PC_Append((void *)&pad, 4-(pc_Address%4)); + } + + PC_WriteInt(pc_Address - lenadr - 4, lenadr); +} + +static void Encrypt(void *data, int key, int len) +{ + int p = (byte)key, i; + + for(i = 0; i < len; ++i) + { + ((byte *)data)[i] ^= (byte)(p+(i>>1)); + } +} diff --git a/strlist.h b/strlist.h index 668d264..0b50237 100644 --- a/strlist.h +++ b/strlist.h @@ -1,38 +1,38 @@ - -//************************************************************************** -//** -//** strlist.h -//** -//************************************************************************** - -#ifndef __STRLIST_H__ -#define __STRLIST_H__ - -// HEADER FILES ------------------------------------------------------------ - -#include "common.h" - -// MACROS ------------------------------------------------------------------ - -// TYPES ------------------------------------------------------------------- - -// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- - -void STR_Init(void); -int STR_Find(char *name); -char *STR_Get(int index); -void STR_WriteStrings(void); -void STR_WriteList(void); -int STR_FindInList(int list, char *name); -int STR_FindInListInsensitive(int list, char *name); -int STR_AppendToList(int list, char *name); -const char *STR_GetString(int list, int index); -void STR_WriteChunk(boolean encrypt); -void STR_WriteListChunk(int list, int id, boolean quad); -int STR_ListSize(); - -// PUBLIC DATA DECLARATIONS ------------------------------------------------ - -extern int NumStringLists; - -#endif + +//************************************************************************** +//** +//** strlist.h +//** +//************************************************************************** + +#ifndef __STRLIST_H__ +#define __STRLIST_H__ + +// HEADER FILES ------------------------------------------------------------ + +#include "common.h" + +// MACROS ------------------------------------------------------------------ + +// TYPES ------------------------------------------------------------------- + +// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- + +void STR_Init(void); +int STR_Find(char *name); +char *STR_Get(int index); +void STR_WriteStrings(void); +void STR_WriteList(void); +int STR_FindInList(int list, char *name); +int STR_FindInListInsensitive(int list, char *name); +int STR_AppendToList(int list, char *name); +const char *STR_GetString(int list, int index); +void STR_WriteChunk(boolean encrypt); +void STR_WriteListChunk(int list, int id, boolean quad); +int STR_ListSize(); + +// PUBLIC DATA DECLARATIONS ------------------------------------------------ + +extern int NumStringLists; + +#endif diff --git a/symbol.c b/symbol.c index d16342e..d60dd8c 100644 --- a/symbol.c +++ b/symbol.c @@ -1,607 +1,607 @@ - -//************************************************************************** -//** -//** symbol.c -//** -//************************************************************************** - -// HEADER FILES ------------------------------------------------------------ - -#include -#include -#include "common.h" -#include "symbol.h" -#include "misc.h" -#include "parse.h" - -// MACROS ------------------------------------------------------------------ - -// TYPES ------------------------------------------------------------------- - -typedef struct -{ - char *name; - pcd_t directCommand; - pcd_t stackCommand; - int argCount; - int optMask; - int outMask; - boolean hasReturnValue; - boolean latent; -} internFuncDef_t; - -// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- - -// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- - -// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- - -static symbolNode_t *Find(char *name, symbolNode_t *root); -static symbolNode_t *Insert(char *name, symbolType_t type, - symbolNode_t **root); -static void FreeNodes(symbolNode_t *root); -static void FreeNodesAtDepth(symbolNode_t **root, int depth); -static void DeleteNode(symbolNode_t *node, symbolNode_t **parent_p); -static void ClearShared(symbolNode_t *root); - -// EXTERNAL DATA DECLARATIONS ---------------------------------------------- - -// PUBLIC DATA DEFINITIONS ------------------------------------------------- - -// PRIVATE DATA DEFINITIONS ------------------------------------------------ - -static symbolNode_t *LocalRoot; -static symbolNode_t *GlobalRoot; - -static internFuncDef_t InternalFunctions[] = -{ - { "tagwait", PCD_TAGWAITDIRECT, PCD_TAGWAIT, 1, 0, 0, NO, YES }, - { "polywait", PCD_POLYWAITDIRECT, PCD_POLYWAIT, 1, 0, 0, NO, YES }, - { "scriptwait", PCD_SCRIPTWAITDIRECT, PCD_SCRIPTWAIT, 1, 0, 0, NO, YES }, - { "namedscriptwait", PCD_NOP, PCD_SCRIPTWAITNAMED, 1, 0, 0, NO, YES }, - { "delay", PCD_DELAYDIRECT, PCD_DELAY, 1, 0, 0, NO, YES }, - { "random", PCD_RANDOMDIRECT, PCD_RANDOM, 2, 0, 0, YES, NO }, - { "thingcount", PCD_THINGCOUNTDIRECT, PCD_THINGCOUNT, 2, 0, 0, YES, NO }, - { "thingcountname", PCD_NOP, PCD_THINGCOUNTNAME, 2, 0, 0, YES, NO }, - { "changefloor", PCD_CHANGEFLOORDIRECT, PCD_CHANGEFLOOR, 2, 0, 0, NO, NO }, - { "changeceiling", PCD_CHANGECEILINGDIRECT, PCD_CHANGECEILING, 2, 0, 0, NO, NO }, - { "lineside", PCD_NOP, PCD_LINESIDE, 0, 0, 0, YES, NO }, - { "clearlinespecial", PCD_NOP, PCD_CLEARLINESPECIAL, 0, 0, 0, NO, NO }, - { "playercount", PCD_NOP, PCD_PLAYERCOUNT, 0, 0, 0, YES, NO }, - { "gametype", PCD_NOP, PCD_GAMETYPE, 0, 0, 0, YES, NO }, - { "gameskill", PCD_NOP, PCD_GAMESKILL, 0, 0, 0, YES, NO }, - { "timer", PCD_NOP, PCD_TIMER, 0, 0, 0, YES, NO }, - { "sectorsound", PCD_NOP, PCD_SECTORSOUND, 2, 0, 0, NO, NO }, - { "ambientsound", PCD_NOP, PCD_AMBIENTSOUND, 2, 0, 0, NO, NO }, - { "soundsequence", PCD_NOP, PCD_SOUNDSEQUENCE, 1, 0, 0, NO, NO }, - { "setlinetexture", PCD_NOP, PCD_SETLINETEXTURE, 4, 0, 0, NO, NO }, - { "setlineblocking", PCD_NOP, PCD_SETLINEBLOCKING, 2, 0, 0, NO, NO }, - { "setlinespecial", PCD_NOP, PCD_SETLINESPECIAL, 7, 4|8|16|32|64, 0, NO, NO }, - { "thingsound", PCD_NOP, PCD_THINGSOUND, 3, 0, 0, NO, NO }, - { "activatorsound", PCD_NOP, PCD_ACTIVATORSOUND, 2, 0, 0, NO, NO }, - { "localambientsound", PCD_NOP, PCD_LOCALAMBIENTSOUND, 2, 0, 0, NO, NO }, - { "setlinemonsterblocking", PCD_NOP, PCD_SETLINEMONSTERBLOCKING, 2, 0, 0, NO, NO }, - { "fixedmul", PCD_NOP, PCD_FIXEDMUL, 2, 0, 0, YES, NO }, - { "fixeddiv", PCD_NOP, PCD_FIXEDDIV, 2, 0, 0, YES, NO }, -// [BC] Start of new pcodes - { "playerblueskull", PCD_NOP, PCD_PLAYERBLUESKULL, 0, 0, 0, YES, NO }, - { "playerredskull", PCD_NOP, PCD_PLAYERREDSKULL, 0, 0, 0, YES, NO }, - { "playeryellowskull", PCD_NOP, PCD_PLAYERYELLOWSKULL, 0, 0, 0, YES, NO }, - { "playerbluecard", PCD_NOP, PCD_PLAYERBLUECARD, 0, 0, 0, YES, NO }, - { "playerredcard", PCD_NOP, PCD_PLAYERREDCARD, 0, 0, 0, YES, NO }, - { "playeryellowcard", PCD_NOP, PCD_PLAYERYELLOWCARD, 0, 0, 0, YES, NO }, - { "isnetworkgame", PCD_NOP, PCD_ISNETWORKGAME, 0, 0, 0, YES, NO }, - { "playerteam", PCD_NOP, PCD_PLAYERTEAM, 0, 0, 0, YES, NO }, - { "playerfrags", PCD_NOP, PCD_PLAYERFRAGS, 0, 0, 0, YES, NO }, - { "playerhealth", PCD_NOP, PCD_PLAYERHEALTH, 0, 0, 0, YES, NO }, - { "playerarmorpoints", PCD_NOP, PCD_PLAYERARMORPOINTS, 0, 0, 0, YES, NO }, - { "playerexpert", PCD_NOP, PCD_PLAYEREXPERT, 0, 0, 0, YES, NO }, - { "bluecount", PCD_NOP, PCD_BLUETEAMCOUNT, 0, 0, 0, YES, NO }, - { "redcount", PCD_NOP, PCD_REDTEAMCOUNT, 0, 0, 0, YES, NO }, - { "bluescore", PCD_NOP, PCD_BLUETEAMSCORE, 0, 0, 0, YES, NO }, - { "redscore", PCD_NOP, PCD_REDTEAMSCORE, 0, 0, 0, YES, NO }, - { "isoneflagctf", PCD_NOP, PCD_ISONEFLAGCTF, 0, 0, 0, YES, NO }, - { "getinvasionwave", PCD_NOP, PCD_GETINVASIONWAVE, 0, 0, 0, YES, NO }, - { "getinvasionstate", PCD_NOP, PCD_GETINVASIONSTATE, 0, 0, 0, YES, NO }, - { "music_change", PCD_NOP, PCD_MUSICCHANGE, 2, 0, 0, NO, NO }, - { "consolecommand", PCD_CONSOLECOMMANDDIRECT, PCD_CONSOLECOMMAND, 3, 2|4, 0, NO, NO }, - { "singleplayer", PCD_NOP, PCD_SINGLEPLAYER, 0, 0, 0, YES, NO }, -// [RH] end of Skull Tag functions - { "setgravity", PCD_SETGRAVITYDIRECT, PCD_SETGRAVITY, 1, 0, 0, NO, NO }, - { "setaircontrol", PCD_SETAIRCONTROLDIRECT, PCD_SETAIRCONTROL, 1, 0, 0, NO, NO }, - { "clearinventory", PCD_NOP, PCD_CLEARINVENTORY, 0, 0, 0, NO, NO }, - { "giveinventory", PCD_GIVEINVENTORYDIRECT, PCD_GIVEINVENTORY, 2, 0, 0, NO, NO }, - { "takeinventory", PCD_TAKEINVENTORYDIRECT, PCD_TAKEINVENTORY, 2, 0, 0, NO, NO }, - { "checkinventory", PCD_CHECKINVENTORYDIRECT, PCD_CHECKINVENTORY, 1, 0, 0, YES, NO }, - { "clearactorinventory", PCD_NOP, PCD_CLEARACTORINVENTORY, 1, 0, 0, NO, NO }, - { "giveactorinventory", PCD_NOP, PCD_GIVEACTORINVENTORY, 3, 0, 0, NO, NO }, - { "takeactorinventory", PCD_NOP, PCD_TAKEACTORINVENTORY, 3, 0, 0, NO, NO }, - { "checkactorinventory", PCD_NOP, PCD_CHECKACTORINVENTORY, 2, 0, 0, YES, NO }, - { "spawn", PCD_SPAWNDIRECT, PCD_SPAWN, 6, 16|32, 0, YES, NO }, - { "spawnspot", PCD_SPAWNSPOTDIRECT, PCD_SPAWNSPOT, 4, 4|8, 0, YES, NO }, - { "spawnspotfacing", PCD_NOP, PCD_SPAWNSPOTFACING, 3, 4, 0, YES, NO }, - { "setmusic", PCD_SETMUSICDIRECT, PCD_SETMUSIC, 3, 2|4, 0, NO, NO }, - { "localsetmusic", PCD_LOCALSETMUSICDIRECT, PCD_LOCALSETMUSIC, 3, 2|4, 0, NO, NO }, - { "setstyle", PCD_SETSTYLEDIRECT, PCD_SETSTYLE, 1, 0, 0, NO, NO }, - { "setfont", PCD_SETFONTDIRECT, PCD_SETFONT, 1, 0, 0, NO, NO }, - { "setthingspecial", PCD_NOP, PCD_SETTHINGSPECIAL, 7, 4|8|16|32|64, 0, NO, NO }, - { "fadeto", PCD_NOP, PCD_FADETO, 5, 0, 0, NO, NO }, - { "faderange", PCD_NOP, PCD_FADERANGE, 9, 0, 0, NO, NO }, - { "cancelfade", PCD_NOP, PCD_CANCELFADE, 0, 0, 0, NO, NO }, - { "playmovie", PCD_NOP, PCD_PLAYMOVIE, 1, 0, 0, YES, NO }, - { "setfloortrigger", PCD_NOP, PCD_SETFLOORTRIGGER, 8, 8|16|32|64|128, 0, NO, NO }, - { "setceilingtrigger", PCD_NOP, PCD_SETCEILINGTRIGGER, 8, 8|16|32|64|128, 0, NO, NO }, - { "setactorposition", PCD_NOP, PCD_SETACTORPOSITION, 5, 0, 0, YES, NO }, - { "getactorx", PCD_NOP, PCD_GETACTORX, 1, 0, 0, YES, NO }, - { "getactory", PCD_NOP, PCD_GETACTORY, 1, 0, 0, YES, NO }, - { "getactorz", PCD_NOP, PCD_GETACTORZ, 1, 0, 0, YES, NO }, - { "getactorfloorz", PCD_NOP, PCD_GETACTORFLOORZ, 1, 0, 0, YES, NO }, - { "getactorceilingz", PCD_NOP, PCD_GETACTORCEILINGZ, 1, 0, 0, YES, NO }, - { "getactorangle", PCD_NOP, PCD_GETACTORANGLE, 1, 0, 0, YES, NO }, - { "writetoini", PCD_NOP, PCD_WRITETOINI, 3, 0, 0, NO, NO }, - { "getfromini", PCD_NOP, PCD_GETFROMINI, 3, 0, 0, YES, NO }, - { "sin", PCD_NOP, PCD_SIN, 1, 0, 0, YES, NO }, - { "cos", PCD_NOP, PCD_COS, 1, 0, 0, YES, NO }, - { "vectorangle", PCD_NOP, PCD_VECTORANGLE, 2, 0, 0, YES, NO }, - { "checkweapon", PCD_NOP, PCD_CHECKWEAPON, 1, 0, 0, YES, NO }, - { "setweapon", PCD_NOP, PCD_SETWEAPON, 1, 0, 0, YES, NO }, - { "setmarineweapon", PCD_NOP, PCD_SETMARINEWEAPON, 2, 0, 0, NO, NO }, - { "setactorproperty", PCD_NOP, PCD_SETACTORPROPERTY, 3, 0, 0, NO, NO }, - { "getactorproperty", PCD_NOP, PCD_GETACTORPROPERTY, 2, 0, 0, YES, NO }, - { "playernumber", PCD_NOP, PCD_PLAYERNUMBER, 0, 0, 0, YES, NO }, - { "activatortid", PCD_NOP, PCD_ACTIVATORTID, 0, 0, 0, YES, NO }, - { "setmarinesprite", PCD_NOP, PCD_SETMARINESPRITE, 2, 0, 0, NO, NO }, - { "getscreenwidth", PCD_NOP, PCD_GETSCREENWIDTH, 0, 0, 0, YES, NO }, - { "getscreenheight", PCD_NOP, PCD_GETSCREENHEIGHT, 0, 0, 0, YES, NO }, - { "thing_projectile2", PCD_NOP, PCD_THING_PROJECTILE2, 7, 0, 0, NO, NO }, - { "strlen", PCD_NOP, PCD_STRLEN, 1, 0, 0, YES, NO }, - { "sethudsize", PCD_NOP, PCD_SETHUDSIZE, 3, 0, 0, NO, NO }, - { "getcvar", PCD_NOP, PCD_GETCVAR, 1, 0, 0, YES, NO }, - { "setresultvalue", PCD_NOP, PCD_SETRESULTVALUE, 1, 0, 0, NO, NO }, - { "getlinerowoffset", PCD_NOP, PCD_GETLINEROWOFFSET, 0, 0, 0, YES, NO }, - { "getsectorfloorz", PCD_NOP, PCD_GETSECTORFLOORZ, 3, 0, 0, YES, NO }, - { "getsectorceilingz", PCD_NOP, PCD_GETSECTORCEILINGZ, 3, 0, 0, YES, NO }, - { "getsigilpieces", PCD_NOP, PCD_GETSIGILPIECES, 0, 0, 0, YES, NO }, - { "getlevelinfo", PCD_NOP, PCD_GETLEVELINFO, 1, 0, 0, YES, NO }, - { "changesky", PCD_NOP, PCD_CHANGESKY, 2, 0, 0, NO, NO }, - { "playeringame", PCD_NOP, PCD_PLAYERINGAME, 1, 0, 0, YES, NO }, - { "playerisbot", PCD_NOP, PCD_PLAYERISBOT, 1, 0, 0, YES, NO }, - { "setcameratotexture", PCD_NOP, PCD_SETCAMERATOTEXTURE, 3, 0, 0, NO, NO }, - { "grabinput", PCD_NOP, PCD_GRABINPUT, 2, 0, 0, NO, NO }, - { "setmousepointer", PCD_NOP, PCD_SETMOUSEPOINTER, 3, 0, 0, NO, NO }, - { "movemousepointer", PCD_NOP, PCD_MOVEMOUSEPOINTER, 2, 0, 0, NO, NO }, - { "getammocapacity", PCD_NOP, PCD_GETAMMOCAPACITY, 1, 0, 0, YES, NO }, - { "setammocapacity", PCD_NOP, PCD_SETAMMOCAPACITY, 2, 0, 0, NO, NO }, - { "setactorangle", PCD_NOP, PCD_SETACTORANGLE, 2, 0, 0, NO, NO }, - { "spawnprojectile", PCD_NOP, PCD_SPAWNPROJECTILE, 7, 0, 0, NO, NO }, - { "getsectorlightlevel", PCD_NOP, PCD_GETSECTORLIGHTLEVEL, 1, 0, 0, YES, NO }, - { "playerclass", PCD_NOP, PCD_PLAYERCLASS, 1, 0, 0, YES, NO }, - { "getplayerinfo", PCD_NOP, PCD_GETPLAYERINFO, 2, 0, 0, YES, NO }, - { "changelevel", PCD_NOP, PCD_CHANGELEVEL, 4, 8, 0, NO, NO }, - { "sectordamage", PCD_NOP, PCD_SECTORDAMAGE, 5, 0, 0, NO, NO }, - { "replacetextures", PCD_NOP, PCD_REPLACETEXTURES, 3, 4, 0, NO, NO }, - { "getactorpitch", PCD_NOP, PCD_GETACTORPITCH, 1, 0, 0, YES, NO }, - { "setactorpitch", PCD_NOP, PCD_SETACTORPITCH, 2, 0, 0, NO, NO }, - { "setactorstate", PCD_NOP, PCD_SETACTORSTATE, 3, 4, 0, YES, NO }, - { "thing_damage2", PCD_NOP, PCD_THINGDAMAGE2, 3, 0, 0, YES, NO }, - { "useinventory", PCD_NOP, PCD_USEINVENTORY, 1, 0, 0, YES, NO }, - { "useactorinventory", PCD_NOP, PCD_USEACTORINVENTORY, 2, 0, 0, YES, NO }, - { "checkactorceilingtexture", PCD_NOP, PCD_CHECKACTORCEILINGTEXTURE, 2, 0, 0, YES, NO }, - { "checkactorfloortexture", PCD_NOP, PCD_CHECKACTORFLOORTEXTURE, 2, 0, 0, YES, NO }, - { "getactorlightlevel", PCD_NOP, PCD_GETACTORLIGHTLEVEL, 1, 0, 0, YES, NO }, - { "setmugshotstate", PCD_NOP, PCD_SETMUGSHOTSTATE, 1, 0, 0, NO, NO }, - { "thingcountsector", PCD_NOP, PCD_THINGCOUNTSECTOR, 3, 0, 0, YES, NO }, - { "thingcountnamesector", PCD_NOP, PCD_THINGCOUNTNAMESECTOR, 3, 0, 0, YES, NO }, - { "checkplayercamera", PCD_NOP, PCD_CHECKPLAYERCAMERA, 1, 0, 0, YES, NO }, - { "unmorphactor", PCD_NOP, PCD_UNMORPHACTOR, 2, 2, 0, YES, NO }, - { "getplayerinput", PCD_NOP, PCD_GETPLAYERINPUT, 2, 0, 0, YES, NO }, - { "classifyactor", PCD_NOP, PCD_CLASSIFYACTOR, 1, 0, 0, YES, NO }, - - { NULL, PCD_NOP, PCD_NOP, 0, 0, 0, NO, NO } -}; - -static char *SymbolTypeNames[] = -{ - "SY_DUMMY", - "SY_LABEL", - "SY_SCRIPTVAR", - "SY_SCRIPTALIAS", - "SY_MAPVAR", - "SY_WORLDVAR", - "SY_GLOBALVAR", - "SY_SCRIPTARRAY", - "SY_MAPARRAY", - "SY_WORLDARRAY", - "SY_GLOBALARRAY", - "SY_SPECIAL", - "SY_CONSTANT", - "SY_INTERNFUNC", - "SY_SCRIPTFUNC" -}; - -// CODE -------------------------------------------------------------------- - -//========================================================================== -// -// SY_Init -// -//========================================================================== - -void SY_Init(void) -{ - symbolNode_t *sym; - internFuncDef_t *def; - - LocalRoot = NULL; - GlobalRoot = NULL; - for(def = InternalFunctions; def->name != NULL; def++) - { - sym = SY_InsertGlobal(def->name, SY_INTERNFUNC); - sym->info.internFunc.directCommand = def->directCommand; - sym->info.internFunc.stackCommand = def->stackCommand; - sym->info.internFunc.argCount = def->argCount; - sym->info.internFunc.optMask = def->optMask; - sym->info.internFunc.outMask = def->outMask; - sym->info.internFunc.hasReturnValue = def->hasReturnValue; - sym->info.internFunc.latent = def->latent; - } -} - -//========================================================================== -// -// SY_Find -// -//========================================================================== - -symbolNode_t *SY_Find(char *name) -{ - symbolNode_t *node; - - if((node = SY_FindGlobal(name)) == NULL) - { - return SY_FindLocal(name); - } - return node; -} - -//========================================================================== -// -// SY_FindGlobal -// -//========================================================================== - -symbolNode_t *SY_FindGlobal(char *name) -{ - symbolNode_t *sym = Find(name, GlobalRoot); - if(sym != NULL && sym->unused) - { - MS_Message(MSG_DEBUG, "Symbol %s marked as used.\n", name); - sym->unused = NO; - if(sym->type == SY_SCRIPTFUNC) - { - PC_AddFunction(sym, 0, NULL); - } - else if(sym->type == SY_MAPVAR) - { - if(pa_MapVarCount >= MAX_MAP_VARIABLES) - { - ERR_Error(ERR_TOO_MANY_MAP_VARS, YES); - } - else - { - sym->info.var.index = pa_MapVarCount++; - PC_NameMapVariable(sym->info.var.index, sym); - } - } - else if(sym->type == SY_MAPARRAY) - { - if(pa_MapVarCount >= MAX_MAP_VARIABLES) - { - ERR_Error(ERR_TOO_MANY_MAP_VARS, YES); - } - else - { - sym->info.array.index = pa_MapVarCount++; - PC_NameMapVariable(sym->info.array.index, sym); - if(sym->type == SY_MAPARRAY) - { - PC_AddArray(sym->info.array.index, sym->info.array.size); - } - } - } - } - return sym; -} - -//========================================================================== -// -// SY_Findlocal -// -//========================================================================== - -symbolNode_t *SY_FindLocal(char *name) -{ - return Find(name, LocalRoot); -} - -//========================================================================== -// -// Find -// -//========================================================================== - -static symbolNode_t *Find(char *name, symbolNode_t *root) -{ - int compare; - symbolNode_t *node; - - node = root; - while(node != NULL) - { - compare = strcmp(name, node->name); - if(compare == 0) - { - if(node->type != SY_DUMMY) - { - return node; - } - else - { - return NULL; - } - } - node = compare < 0 ? node->left : node->right; - } - return NULL; -} - -//========================================================================== -// -// SY_InsertLocal -// -//========================================================================== - -symbolNode_t *SY_InsertLocal(char *name, symbolType_t type) -{ - if(Find(name, GlobalRoot)) - { - ERR_Error(ERR_LOCAL_VAR_SHADOWED, YES); - } - MS_Message(MSG_DEBUG, "Inserting local identifier: %s (%s)\n", - name, SymbolTypeNames[type]); - return Insert(name, type, &LocalRoot); -} - -//========================================================================== -// -// SY_InsertGlobal -// -//========================================================================== - -symbolNode_t *SY_InsertGlobal(char *name, symbolType_t type) -{ - MS_Message(MSG_DEBUG, "Inserting global identifier: %s (%s)\n", - name, SymbolTypeNames[type]); - return Insert(name, type, &GlobalRoot); -} - -//========================================================================== -// -// SY_InsertGlobalUnique -// -//========================================================================== - -symbolNode_t *SY_InsertGlobalUnique(char *name, symbolType_t type) -{ - if(SY_FindGlobal(name) != NULL) - { // Redefined - ERR_Exit(ERR_REDEFINED_IDENTIFIER, YES, name); - } - return SY_InsertGlobal(name, type); -} - -//========================================================================== -// -// Insert -// -//========================================================================== - -static symbolNode_t *Insert(char *name, symbolType_t type, - symbolNode_t **root) -{ - int compare; - symbolNode_t *newNode; - symbolNode_t *node; - - newNode = MS_Alloc(sizeof(symbolNode_t), ERR_NO_SYMBOL_MEM); - newNode->name = MS_Alloc(strlen(name)+1, ERR_NO_SYMBOL_MEM); - strcpy(newNode->name, name); - newNode->left = newNode->right = NULL; - newNode->type = type; - newNode->unused = NO; - newNode->imported = ImportMode == IMPORT_Importing; - while((node = *root) != NULL) - { - compare = strcmp(name, node->name); - root = compare < 0 ? &(node->left) : &(node->right); - } - *root = newNode; - return(newNode); -} - -//========================================================================== -// -// SY_FreeLocals -// -//========================================================================== - -void SY_FreeLocals(void) -{ - MS_Message(MSG_DEBUG, "Freeing local identifiers\n"); - FreeNodes(LocalRoot); - LocalRoot = NULL; -} - -//========================================================================== -// -// SY_FreeGlobals -// -//========================================================================== - -void SY_FreeGlobals(void) -{ - MS_Message(MSG_DEBUG, "Freeing global identifiers\n"); - FreeNodes(GlobalRoot); - GlobalRoot = NULL; -} - -//========================================================================== -// -// FreeNodes -// -//========================================================================== - -static void FreeNodes(symbolNode_t *root) -{ - if(root == NULL) - { - return; - } - FreeNodes(root->left); - FreeNodes(root->right); - free(root->name); - free(root); -} - -//========================================================================== -// -// SY_FreeConstants -// -//========================================================================== - -void SY_FreeConstants(int depth) -{ - MS_Message(MSG_DEBUG, "Freeing constants for depth %d\n", depth); - FreeNodesAtDepth(&GlobalRoot, depth); -} - -//========================================================================== -// -// FreeNodesAtDepth -// -// Like FreeNodes, but it only frees the nodes of type SY_CONSTANT that are -// marked at the specified depth. The other nodes are relinked to maintain a -// proper binary tree. -// -//========================================================================== - -static void FreeNodesAtDepth(symbolNode_t **root, int depth) -{ - symbolNode_t *node = *root; - - if(node == NULL) - { - return; - } - FreeNodesAtDepth(&node->left, depth); - FreeNodesAtDepth(&node->right, depth); - if(node->type == SY_CONSTANT && node->info.constant.fileDepth == depth) - { - MS_Message(MSG_DEBUG, "Deleting constant %s\n", node->name); - DeleteNode(node, root); - } -} - -//========================================================================== -// -// DeleteNode -// -//========================================================================== - -static void DeleteNode(symbolNode_t *node, symbolNode_t **parent_p) -{ - symbolNode_t **temp; - char *nametemp; - - if(node->type == SY_CONSTANT && node->info.constant.strValue != NULL) - { - free(node->info.constant.strValue); - node->info.constant.strValue = NULL; - } - if(node->left == NULL) - { - *parent_p = node->right; - free(node->name); - free(node); - } - else if(node->right == NULL) - { - *parent_p = node->left; - free(node->name); - free(node); - } - else - { - // "Randomly" pick the in-order successor or predecessor to take - // the place of the deleted node. - if(rand() & 1) - { - // predecessor - temp = &node->left; - while((*temp)->right != NULL) - { - temp = &(*temp)->right; - } - } - else - { - // successor - temp = &node->right; - while((*temp)->left != NULL) - { - temp = &(*temp)->left; - } - } - nametemp = node->name; - node->name = (*temp)->name; - (*temp)->name = nametemp; - node->type = (*temp)->type; - node->unused = (*temp)->unused; - node->imported = (*temp)->imported; - node->info = (*temp)->info; - DeleteNode(*temp, temp); - } -} - -//========================================================================== -// -// SY_ClearShared -// -//========================================================================== - -void SY_ClearShared(void) -{ - MS_Message(MSG_DEBUG, "Marking library exports as unused\n"); - ClearShared(GlobalRoot); -} - -//========================================================================== -// -// ClearShared -// -//========================================================================== - -static void ClearShared(symbolNode_t *root) -{ - while(root != NULL) - { - if( root->type == SY_SCRIPTFUNC || - root->type == SY_MAPVAR || - root->type == SY_MAPARRAY) - { - root->unused = YES; - } - ClearShared(root->left); - root = root->right; - } -} + +//************************************************************************** +//** +//** symbol.c +//** +//************************************************************************** + +// HEADER FILES ------------------------------------------------------------ + +#include +#include +#include "common.h" +#include "symbol.h" +#include "misc.h" +#include "parse.h" + +// MACROS ------------------------------------------------------------------ + +// TYPES ------------------------------------------------------------------- + +typedef struct +{ + char *name; + pcd_t directCommand; + pcd_t stackCommand; + int argCount; + int optMask; + int outMask; + boolean hasReturnValue; + boolean latent; +} internFuncDef_t; + +// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- + +// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- + +// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- + +static symbolNode_t *Find(char *name, symbolNode_t *root); +static symbolNode_t *Insert(char *name, symbolType_t type, + symbolNode_t **root); +static void FreeNodes(symbolNode_t *root); +static void FreeNodesAtDepth(symbolNode_t **root, int depth); +static void DeleteNode(symbolNode_t *node, symbolNode_t **parent_p); +static void ClearShared(symbolNode_t *root); + +// EXTERNAL DATA DECLARATIONS ---------------------------------------------- + +// PUBLIC DATA DEFINITIONS ------------------------------------------------- + +// PRIVATE DATA DEFINITIONS ------------------------------------------------ + +static symbolNode_t *LocalRoot; +static symbolNode_t *GlobalRoot; + +static internFuncDef_t InternalFunctions[] = +{ + { "tagwait", PCD_TAGWAITDIRECT, PCD_TAGWAIT, 1, 0, 0, NO, YES }, + { "polywait", PCD_POLYWAITDIRECT, PCD_POLYWAIT, 1, 0, 0, NO, YES }, + { "scriptwait", PCD_SCRIPTWAITDIRECT, PCD_SCRIPTWAIT, 1, 0, 0, NO, YES }, + { "namedscriptwait", PCD_NOP, PCD_SCRIPTWAITNAMED, 1, 0, 0, NO, YES }, + { "delay", PCD_DELAYDIRECT, PCD_DELAY, 1, 0, 0, NO, YES }, + { "random", PCD_RANDOMDIRECT, PCD_RANDOM, 2, 0, 0, YES, NO }, + { "thingcount", PCD_THINGCOUNTDIRECT, PCD_THINGCOUNT, 2, 0, 0, YES, NO }, + { "thingcountname", PCD_NOP, PCD_THINGCOUNTNAME, 2, 0, 0, YES, NO }, + { "changefloor", PCD_CHANGEFLOORDIRECT, PCD_CHANGEFLOOR, 2, 0, 0, NO, NO }, + { "changeceiling", PCD_CHANGECEILINGDIRECT, PCD_CHANGECEILING, 2, 0, 0, NO, NO }, + { "lineside", PCD_NOP, PCD_LINESIDE, 0, 0, 0, YES, NO }, + { "clearlinespecial", PCD_NOP, PCD_CLEARLINESPECIAL, 0, 0, 0, NO, NO }, + { "playercount", PCD_NOP, PCD_PLAYERCOUNT, 0, 0, 0, YES, NO }, + { "gametype", PCD_NOP, PCD_GAMETYPE, 0, 0, 0, YES, NO }, + { "gameskill", PCD_NOP, PCD_GAMESKILL, 0, 0, 0, YES, NO }, + { "timer", PCD_NOP, PCD_TIMER, 0, 0, 0, YES, NO }, + { "sectorsound", PCD_NOP, PCD_SECTORSOUND, 2, 0, 0, NO, NO }, + { "ambientsound", PCD_NOP, PCD_AMBIENTSOUND, 2, 0, 0, NO, NO }, + { "soundsequence", PCD_NOP, PCD_SOUNDSEQUENCE, 1, 0, 0, NO, NO }, + { "setlinetexture", PCD_NOP, PCD_SETLINETEXTURE, 4, 0, 0, NO, NO }, + { "setlineblocking", PCD_NOP, PCD_SETLINEBLOCKING, 2, 0, 0, NO, NO }, + { "setlinespecial", PCD_NOP, PCD_SETLINESPECIAL, 7, 4|8|16|32|64, 0, NO, NO }, + { "thingsound", PCD_NOP, PCD_THINGSOUND, 3, 0, 0, NO, NO }, + { "activatorsound", PCD_NOP, PCD_ACTIVATORSOUND, 2, 0, 0, NO, NO }, + { "localambientsound", PCD_NOP, PCD_LOCALAMBIENTSOUND, 2, 0, 0, NO, NO }, + { "setlinemonsterblocking", PCD_NOP, PCD_SETLINEMONSTERBLOCKING, 2, 0, 0, NO, NO }, + { "fixedmul", PCD_NOP, PCD_FIXEDMUL, 2, 0, 0, YES, NO }, + { "fixeddiv", PCD_NOP, PCD_FIXEDDIV, 2, 0, 0, YES, NO }, +// [BC] Start of new pcodes + { "playerblueskull", PCD_NOP, PCD_PLAYERBLUESKULL, 0, 0, 0, YES, NO }, + { "playerredskull", PCD_NOP, PCD_PLAYERREDSKULL, 0, 0, 0, YES, NO }, + { "playeryellowskull", PCD_NOP, PCD_PLAYERYELLOWSKULL, 0, 0, 0, YES, NO }, + { "playerbluecard", PCD_NOP, PCD_PLAYERBLUECARD, 0, 0, 0, YES, NO }, + { "playerredcard", PCD_NOP, PCD_PLAYERREDCARD, 0, 0, 0, YES, NO }, + { "playeryellowcard", PCD_NOP, PCD_PLAYERYELLOWCARD, 0, 0, 0, YES, NO }, + { "isnetworkgame", PCD_NOP, PCD_ISNETWORKGAME, 0, 0, 0, YES, NO }, + { "playerteam", PCD_NOP, PCD_PLAYERTEAM, 0, 0, 0, YES, NO }, + { "playerfrags", PCD_NOP, PCD_PLAYERFRAGS, 0, 0, 0, YES, NO }, + { "playerhealth", PCD_NOP, PCD_PLAYERHEALTH, 0, 0, 0, YES, NO }, + { "playerarmorpoints", PCD_NOP, PCD_PLAYERARMORPOINTS, 0, 0, 0, YES, NO }, + { "playerexpert", PCD_NOP, PCD_PLAYEREXPERT, 0, 0, 0, YES, NO }, + { "bluecount", PCD_NOP, PCD_BLUETEAMCOUNT, 0, 0, 0, YES, NO }, + { "redcount", PCD_NOP, PCD_REDTEAMCOUNT, 0, 0, 0, YES, NO }, + { "bluescore", PCD_NOP, PCD_BLUETEAMSCORE, 0, 0, 0, YES, NO }, + { "redscore", PCD_NOP, PCD_REDTEAMSCORE, 0, 0, 0, YES, NO }, + { "isoneflagctf", PCD_NOP, PCD_ISONEFLAGCTF, 0, 0, 0, YES, NO }, + { "getinvasionwave", PCD_NOP, PCD_GETINVASIONWAVE, 0, 0, 0, YES, NO }, + { "getinvasionstate", PCD_NOP, PCD_GETINVASIONSTATE, 0, 0, 0, YES, NO }, + { "music_change", PCD_NOP, PCD_MUSICCHANGE, 2, 0, 0, NO, NO }, + { "consolecommand", PCD_CONSOLECOMMANDDIRECT, PCD_CONSOLECOMMAND, 3, 2|4, 0, NO, NO }, + { "singleplayer", PCD_NOP, PCD_SINGLEPLAYER, 0, 0, 0, YES, NO }, +// [RH] end of Skull Tag functions + { "setgravity", PCD_SETGRAVITYDIRECT, PCD_SETGRAVITY, 1, 0, 0, NO, NO }, + { "setaircontrol", PCD_SETAIRCONTROLDIRECT, PCD_SETAIRCONTROL, 1, 0, 0, NO, NO }, + { "clearinventory", PCD_NOP, PCD_CLEARINVENTORY, 0, 0, 0, NO, NO }, + { "giveinventory", PCD_GIVEINVENTORYDIRECT, PCD_GIVEINVENTORY, 2, 0, 0, NO, NO }, + { "takeinventory", PCD_TAKEINVENTORYDIRECT, PCD_TAKEINVENTORY, 2, 0, 0, NO, NO }, + { "checkinventory", PCD_CHECKINVENTORYDIRECT, PCD_CHECKINVENTORY, 1, 0, 0, YES, NO }, + { "clearactorinventory", PCD_NOP, PCD_CLEARACTORINVENTORY, 1, 0, 0, NO, NO }, + { "giveactorinventory", PCD_NOP, PCD_GIVEACTORINVENTORY, 3, 0, 0, NO, NO }, + { "takeactorinventory", PCD_NOP, PCD_TAKEACTORINVENTORY, 3, 0, 0, NO, NO }, + { "checkactorinventory", PCD_NOP, PCD_CHECKACTORINVENTORY, 2, 0, 0, YES, NO }, + { "spawn", PCD_SPAWNDIRECT, PCD_SPAWN, 6, 16|32, 0, YES, NO }, + { "spawnspot", PCD_SPAWNSPOTDIRECT, PCD_SPAWNSPOT, 4, 4|8, 0, YES, NO }, + { "spawnspotfacing", PCD_NOP, PCD_SPAWNSPOTFACING, 3, 4, 0, YES, NO }, + { "setmusic", PCD_SETMUSICDIRECT, PCD_SETMUSIC, 3, 2|4, 0, NO, NO }, + { "localsetmusic", PCD_LOCALSETMUSICDIRECT, PCD_LOCALSETMUSIC, 3, 2|4, 0, NO, NO }, + { "setstyle", PCD_SETSTYLEDIRECT, PCD_SETSTYLE, 1, 0, 0, NO, NO }, + { "setfont", PCD_SETFONTDIRECT, PCD_SETFONT, 1, 0, 0, NO, NO }, + { "setthingspecial", PCD_NOP, PCD_SETTHINGSPECIAL, 7, 4|8|16|32|64, 0, NO, NO }, + { "fadeto", PCD_NOP, PCD_FADETO, 5, 0, 0, NO, NO }, + { "faderange", PCD_NOP, PCD_FADERANGE, 9, 0, 0, NO, NO }, + { "cancelfade", PCD_NOP, PCD_CANCELFADE, 0, 0, 0, NO, NO }, + { "playmovie", PCD_NOP, PCD_PLAYMOVIE, 1, 0, 0, YES, NO }, + { "setfloortrigger", PCD_NOP, PCD_SETFLOORTRIGGER, 8, 8|16|32|64|128, 0, NO, NO }, + { "setceilingtrigger", PCD_NOP, PCD_SETCEILINGTRIGGER, 8, 8|16|32|64|128, 0, NO, NO }, + { "setactorposition", PCD_NOP, PCD_SETACTORPOSITION, 5, 0, 0, YES, NO }, + { "getactorx", PCD_NOP, PCD_GETACTORX, 1, 0, 0, YES, NO }, + { "getactory", PCD_NOP, PCD_GETACTORY, 1, 0, 0, YES, NO }, + { "getactorz", PCD_NOP, PCD_GETACTORZ, 1, 0, 0, YES, NO }, + { "getactorfloorz", PCD_NOP, PCD_GETACTORFLOORZ, 1, 0, 0, YES, NO }, + { "getactorceilingz", PCD_NOP, PCD_GETACTORCEILINGZ, 1, 0, 0, YES, NO }, + { "getactorangle", PCD_NOP, PCD_GETACTORANGLE, 1, 0, 0, YES, NO }, + { "writetoini", PCD_NOP, PCD_WRITETOINI, 3, 0, 0, NO, NO }, + { "getfromini", PCD_NOP, PCD_GETFROMINI, 3, 0, 0, YES, NO }, + { "sin", PCD_NOP, PCD_SIN, 1, 0, 0, YES, NO }, + { "cos", PCD_NOP, PCD_COS, 1, 0, 0, YES, NO }, + { "vectorangle", PCD_NOP, PCD_VECTORANGLE, 2, 0, 0, YES, NO }, + { "checkweapon", PCD_NOP, PCD_CHECKWEAPON, 1, 0, 0, YES, NO }, + { "setweapon", PCD_NOP, PCD_SETWEAPON, 1, 0, 0, YES, NO }, + { "setmarineweapon", PCD_NOP, PCD_SETMARINEWEAPON, 2, 0, 0, NO, NO }, + { "setactorproperty", PCD_NOP, PCD_SETACTORPROPERTY, 3, 0, 0, NO, NO }, + { "getactorproperty", PCD_NOP, PCD_GETACTORPROPERTY, 2, 0, 0, YES, NO }, + { "playernumber", PCD_NOP, PCD_PLAYERNUMBER, 0, 0, 0, YES, NO }, + { "activatortid", PCD_NOP, PCD_ACTIVATORTID, 0, 0, 0, YES, NO }, + { "setmarinesprite", PCD_NOP, PCD_SETMARINESPRITE, 2, 0, 0, NO, NO }, + { "getscreenwidth", PCD_NOP, PCD_GETSCREENWIDTH, 0, 0, 0, YES, NO }, + { "getscreenheight", PCD_NOP, PCD_GETSCREENHEIGHT, 0, 0, 0, YES, NO }, + { "thing_projectile2", PCD_NOP, PCD_THING_PROJECTILE2, 7, 0, 0, NO, NO }, + { "strlen", PCD_NOP, PCD_STRLEN, 1, 0, 0, YES, NO }, + { "sethudsize", PCD_NOP, PCD_SETHUDSIZE, 3, 0, 0, NO, NO }, + { "getcvar", PCD_NOP, PCD_GETCVAR, 1, 0, 0, YES, NO }, + { "setresultvalue", PCD_NOP, PCD_SETRESULTVALUE, 1, 0, 0, NO, NO }, + { "getlinerowoffset", PCD_NOP, PCD_GETLINEROWOFFSET, 0, 0, 0, YES, NO }, + { "getsectorfloorz", PCD_NOP, PCD_GETSECTORFLOORZ, 3, 0, 0, YES, NO }, + { "getsectorceilingz", PCD_NOP, PCD_GETSECTORCEILINGZ, 3, 0, 0, YES, NO }, + { "getsigilpieces", PCD_NOP, PCD_GETSIGILPIECES, 0, 0, 0, YES, NO }, + { "getlevelinfo", PCD_NOP, PCD_GETLEVELINFO, 1, 0, 0, YES, NO }, + { "changesky", PCD_NOP, PCD_CHANGESKY, 2, 0, 0, NO, NO }, + { "playeringame", PCD_NOP, PCD_PLAYERINGAME, 1, 0, 0, YES, NO }, + { "playerisbot", PCD_NOP, PCD_PLAYERISBOT, 1, 0, 0, YES, NO }, + { "setcameratotexture", PCD_NOP, PCD_SETCAMERATOTEXTURE, 3, 0, 0, NO, NO }, + { "grabinput", PCD_NOP, PCD_GRABINPUT, 2, 0, 0, NO, NO }, + { "setmousepointer", PCD_NOP, PCD_SETMOUSEPOINTER, 3, 0, 0, NO, NO }, + { "movemousepointer", PCD_NOP, PCD_MOVEMOUSEPOINTER, 2, 0, 0, NO, NO }, + { "getammocapacity", PCD_NOP, PCD_GETAMMOCAPACITY, 1, 0, 0, YES, NO }, + { "setammocapacity", PCD_NOP, PCD_SETAMMOCAPACITY, 2, 0, 0, NO, NO }, + { "setactorangle", PCD_NOP, PCD_SETACTORANGLE, 2, 0, 0, NO, NO }, + { "spawnprojectile", PCD_NOP, PCD_SPAWNPROJECTILE, 7, 0, 0, NO, NO }, + { "getsectorlightlevel", PCD_NOP, PCD_GETSECTORLIGHTLEVEL, 1, 0, 0, YES, NO }, + { "playerclass", PCD_NOP, PCD_PLAYERCLASS, 1, 0, 0, YES, NO }, + { "getplayerinfo", PCD_NOP, PCD_GETPLAYERINFO, 2, 0, 0, YES, NO }, + { "changelevel", PCD_NOP, PCD_CHANGELEVEL, 4, 8, 0, NO, NO }, + { "sectordamage", PCD_NOP, PCD_SECTORDAMAGE, 5, 0, 0, NO, NO }, + { "replacetextures", PCD_NOP, PCD_REPLACETEXTURES, 3, 4, 0, NO, NO }, + { "getactorpitch", PCD_NOP, PCD_GETACTORPITCH, 1, 0, 0, YES, NO }, + { "setactorpitch", PCD_NOP, PCD_SETACTORPITCH, 2, 0, 0, NO, NO }, + { "setactorstate", PCD_NOP, PCD_SETACTORSTATE, 3, 4, 0, YES, NO }, + { "thing_damage2", PCD_NOP, PCD_THINGDAMAGE2, 3, 0, 0, YES, NO }, + { "useinventory", PCD_NOP, PCD_USEINVENTORY, 1, 0, 0, YES, NO }, + { "useactorinventory", PCD_NOP, PCD_USEACTORINVENTORY, 2, 0, 0, YES, NO }, + { "checkactorceilingtexture", PCD_NOP, PCD_CHECKACTORCEILINGTEXTURE, 2, 0, 0, YES, NO }, + { "checkactorfloortexture", PCD_NOP, PCD_CHECKACTORFLOORTEXTURE, 2, 0, 0, YES, NO }, + { "getactorlightlevel", PCD_NOP, PCD_GETACTORLIGHTLEVEL, 1, 0, 0, YES, NO }, + { "setmugshotstate", PCD_NOP, PCD_SETMUGSHOTSTATE, 1, 0, 0, NO, NO }, + { "thingcountsector", PCD_NOP, PCD_THINGCOUNTSECTOR, 3, 0, 0, YES, NO }, + { "thingcountnamesector", PCD_NOP, PCD_THINGCOUNTNAMESECTOR, 3, 0, 0, YES, NO }, + { "checkplayercamera", PCD_NOP, PCD_CHECKPLAYERCAMERA, 1, 0, 0, YES, NO }, + { "unmorphactor", PCD_NOP, PCD_UNMORPHACTOR, 2, 2, 0, YES, NO }, + { "getplayerinput", PCD_NOP, PCD_GETPLAYERINPUT, 2, 0, 0, YES, NO }, + { "classifyactor", PCD_NOP, PCD_CLASSIFYACTOR, 1, 0, 0, YES, NO }, + + { NULL, PCD_NOP, PCD_NOP, 0, 0, 0, NO, NO } +}; + +static char *SymbolTypeNames[] = +{ + "SY_DUMMY", + "SY_LABEL", + "SY_SCRIPTVAR", + "SY_SCRIPTALIAS", + "SY_MAPVAR", + "SY_WORLDVAR", + "SY_GLOBALVAR", + "SY_SCRIPTARRAY", + "SY_MAPARRAY", + "SY_WORLDARRAY", + "SY_GLOBALARRAY", + "SY_SPECIAL", + "SY_CONSTANT", + "SY_INTERNFUNC", + "SY_SCRIPTFUNC" +}; + +// CODE -------------------------------------------------------------------- + +//========================================================================== +// +// SY_Init +// +//========================================================================== + +void SY_Init(void) +{ + symbolNode_t *sym; + internFuncDef_t *def; + + LocalRoot = NULL; + GlobalRoot = NULL; + for(def = InternalFunctions; def->name != NULL; def++) + { + sym = SY_InsertGlobal(def->name, SY_INTERNFUNC); + sym->info.internFunc.directCommand = def->directCommand; + sym->info.internFunc.stackCommand = def->stackCommand; + sym->info.internFunc.argCount = def->argCount; + sym->info.internFunc.optMask = def->optMask; + sym->info.internFunc.outMask = def->outMask; + sym->info.internFunc.hasReturnValue = def->hasReturnValue; + sym->info.internFunc.latent = def->latent; + } +} + +//========================================================================== +// +// SY_Find +// +//========================================================================== + +symbolNode_t *SY_Find(char *name) +{ + symbolNode_t *node; + + if((node = SY_FindGlobal(name)) == NULL) + { + return SY_FindLocal(name); + } + return node; +} + +//========================================================================== +// +// SY_FindGlobal +// +//========================================================================== + +symbolNode_t *SY_FindGlobal(char *name) +{ + symbolNode_t *sym = Find(name, GlobalRoot); + if(sym != NULL && sym->unused) + { + MS_Message(MSG_DEBUG, "Symbol %s marked as used.\n", name); + sym->unused = NO; + if(sym->type == SY_SCRIPTFUNC) + { + PC_AddFunction(sym, 0, NULL); + } + else if(sym->type == SY_MAPVAR) + { + if(pa_MapVarCount >= MAX_MAP_VARIABLES) + { + ERR_Error(ERR_TOO_MANY_MAP_VARS, YES); + } + else + { + sym->info.var.index = pa_MapVarCount++; + PC_NameMapVariable(sym->info.var.index, sym); + } + } + else if(sym->type == SY_MAPARRAY) + { + if(pa_MapVarCount >= MAX_MAP_VARIABLES) + { + ERR_Error(ERR_TOO_MANY_MAP_VARS, YES); + } + else + { + sym->info.array.index = pa_MapVarCount++; + PC_NameMapVariable(sym->info.array.index, sym); + if(sym->type == SY_MAPARRAY) + { + PC_AddArray(sym->info.array.index, sym->info.array.size); + } + } + } + } + return sym; +} + +//========================================================================== +// +// SY_Findlocal +// +//========================================================================== + +symbolNode_t *SY_FindLocal(char *name) +{ + return Find(name, LocalRoot); +} + +//========================================================================== +// +// Find +// +//========================================================================== + +static symbolNode_t *Find(char *name, symbolNode_t *root) +{ + int compare; + symbolNode_t *node; + + node = root; + while(node != NULL) + { + compare = strcmp(name, node->name); + if(compare == 0) + { + if(node->type != SY_DUMMY) + { + return node; + } + else + { + return NULL; + } + } + node = compare < 0 ? node->left : node->right; + } + return NULL; +} + +//========================================================================== +// +// SY_InsertLocal +// +//========================================================================== + +symbolNode_t *SY_InsertLocal(char *name, symbolType_t type) +{ + if(Find(name, GlobalRoot)) + { + ERR_Error(ERR_LOCAL_VAR_SHADOWED, YES); + } + MS_Message(MSG_DEBUG, "Inserting local identifier: %s (%s)\n", + name, SymbolTypeNames[type]); + return Insert(name, type, &LocalRoot); +} + +//========================================================================== +// +// SY_InsertGlobal +// +//========================================================================== + +symbolNode_t *SY_InsertGlobal(char *name, symbolType_t type) +{ + MS_Message(MSG_DEBUG, "Inserting global identifier: %s (%s)\n", + name, SymbolTypeNames[type]); + return Insert(name, type, &GlobalRoot); +} + +//========================================================================== +// +// SY_InsertGlobalUnique +// +//========================================================================== + +symbolNode_t *SY_InsertGlobalUnique(char *name, symbolType_t type) +{ + if(SY_FindGlobal(name) != NULL) + { // Redefined + ERR_Exit(ERR_REDEFINED_IDENTIFIER, YES, name); + } + return SY_InsertGlobal(name, type); +} + +//========================================================================== +// +// Insert +// +//========================================================================== + +static symbolNode_t *Insert(char *name, symbolType_t type, + symbolNode_t **root) +{ + int compare; + symbolNode_t *newNode; + symbolNode_t *node; + + newNode = MS_Alloc(sizeof(symbolNode_t), ERR_NO_SYMBOL_MEM); + newNode->name = MS_Alloc(strlen(name)+1, ERR_NO_SYMBOL_MEM); + strcpy(newNode->name, name); + newNode->left = newNode->right = NULL; + newNode->type = type; + newNode->unused = NO; + newNode->imported = ImportMode == IMPORT_Importing; + while((node = *root) != NULL) + { + compare = strcmp(name, node->name); + root = compare < 0 ? &(node->left) : &(node->right); + } + *root = newNode; + return(newNode); +} + +//========================================================================== +// +// SY_FreeLocals +// +//========================================================================== + +void SY_FreeLocals(void) +{ + MS_Message(MSG_DEBUG, "Freeing local identifiers\n"); + FreeNodes(LocalRoot); + LocalRoot = NULL; +} + +//========================================================================== +// +// SY_FreeGlobals +// +//========================================================================== + +void SY_FreeGlobals(void) +{ + MS_Message(MSG_DEBUG, "Freeing global identifiers\n"); + FreeNodes(GlobalRoot); + GlobalRoot = NULL; +} + +//========================================================================== +// +// FreeNodes +// +//========================================================================== + +static void FreeNodes(symbolNode_t *root) +{ + if(root == NULL) + { + return; + } + FreeNodes(root->left); + FreeNodes(root->right); + free(root->name); + free(root); +} + +//========================================================================== +// +// SY_FreeConstants +// +//========================================================================== + +void SY_FreeConstants(int depth) +{ + MS_Message(MSG_DEBUG, "Freeing constants for depth %d\n", depth); + FreeNodesAtDepth(&GlobalRoot, depth); +} + +//========================================================================== +// +// FreeNodesAtDepth +// +// Like FreeNodes, but it only frees the nodes of type SY_CONSTANT that are +// marked at the specified depth. The other nodes are relinked to maintain a +// proper binary tree. +// +//========================================================================== + +static void FreeNodesAtDepth(symbolNode_t **root, int depth) +{ + symbolNode_t *node = *root; + + if(node == NULL) + { + return; + } + FreeNodesAtDepth(&node->left, depth); + FreeNodesAtDepth(&node->right, depth); + if(node->type == SY_CONSTANT && node->info.constant.fileDepth == depth) + { + MS_Message(MSG_DEBUG, "Deleting constant %s\n", node->name); + DeleteNode(node, root); + } +} + +//========================================================================== +// +// DeleteNode +// +//========================================================================== + +static void DeleteNode(symbolNode_t *node, symbolNode_t **parent_p) +{ + symbolNode_t **temp; + char *nametemp; + + if(node->type == SY_CONSTANT && node->info.constant.strValue != NULL) + { + free(node->info.constant.strValue); + node->info.constant.strValue = NULL; + } + if(node->left == NULL) + { + *parent_p = node->right; + free(node->name); + free(node); + } + else if(node->right == NULL) + { + *parent_p = node->left; + free(node->name); + free(node); + } + else + { + // "Randomly" pick the in-order successor or predecessor to take + // the place of the deleted node. + if(rand() & 1) + { + // predecessor + temp = &node->left; + while((*temp)->right != NULL) + { + temp = &(*temp)->right; + } + } + else + { + // successor + temp = &node->right; + while((*temp)->left != NULL) + { + temp = &(*temp)->left; + } + } + nametemp = node->name; + node->name = (*temp)->name; + (*temp)->name = nametemp; + node->type = (*temp)->type; + node->unused = (*temp)->unused; + node->imported = (*temp)->imported; + node->info = (*temp)->info; + DeleteNode(*temp, temp); + } +} + +//========================================================================== +// +// SY_ClearShared +// +//========================================================================== + +void SY_ClearShared(void) +{ + MS_Message(MSG_DEBUG, "Marking library exports as unused\n"); + ClearShared(GlobalRoot); +} + +//========================================================================== +// +// ClearShared +// +//========================================================================== + +static void ClearShared(symbolNode_t *root) +{ + while(root != NULL) + { + if( root->type == SY_SCRIPTFUNC || + root->type == SY_MAPVAR || + root->type == SY_MAPARRAY) + { + root->unused = YES; + } + ClearShared(root->left); + root = root->right; + } +} diff --git a/symbol.h b/symbol.h index 901ff46..806621a 100644 --- a/symbol.h +++ b/symbol.h @@ -1,131 +1,131 @@ - -//************************************************************************** -//** -//** symbol.h -//** -//************************************************************************** - -#ifndef __SYMBOL_H__ -#define __SYMBOL_H__ - -// HEADER FILES ------------------------------------------------------------ - -#include "common.h" -#include "pcode.h" - -// MACROS ------------------------------------------------------------------ - -#define MAX_ARRAY_DIMS 8 - -// TYPES ------------------------------------------------------------------- - -typedef enum -{ - SY_DUMMY, - SY_LABEL, - SY_SCRIPTVAR, - SY_SCRIPTALIAS, - SY_MAPVAR, - SY_WORLDVAR, - SY_GLOBALVAR, - SY_SCRIPTARRAY, - SY_MAPARRAY, - SY_WORLDARRAY, - SY_GLOBALARRAY, - SY_SPECIAL, - SY_CONSTANT, - SY_INTERNFUNC, - SY_SCRIPTFUNC -} symbolType_t; - -typedef struct -{ - U_BYTE index; -} symVar_t; - -typedef struct -{ - U_BYTE index; - int dimensions[MAX_ARRAY_DIMS]; - int ndim; - int size; -} symArray_t; - -typedef struct -{ - int address; -} symLabel_t; - -typedef struct -{ - int value; - int argCount; -} symSpecial_t; - -typedef struct -{ - int value; - char *strValue; - int fileDepth; -} symConstant_t; - -typedef struct -{ - pcd_t directCommand; - pcd_t stackCommand; - int argCount; - int optMask; - int outMask; - boolean hasReturnValue; - boolean latent; -} symInternFunc_t; - -typedef struct -{ - int address; - int argCount; - int varCount; - int funcNumber; - boolean hasReturnValue; - int sourceLine; - char *sourceName; - boolean predefined; -} symScriptFunc_t; - -typedef struct symbolNode_s -{ - struct symbolNode_s *left; - struct symbolNode_s *right; - char *name; - symbolType_t type; - boolean unused; - boolean imported; - union - { - symVar_t var; - symArray_t array; - symLabel_t label; - symSpecial_t special; - symConstant_t constant; - symInternFunc_t internFunc; - symScriptFunc_t scriptFunc; - } info; -} symbolNode_t; - -// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- - -void SY_Init(void); -symbolNode_t *SY_Find(char *name); -symbolNode_t *SY_FindLocal(char *name); -symbolNode_t *SY_FindGlobal(char *name); -symbolNode_t *SY_InsertLocal(char *name, symbolType_t type); -symbolNode_t *SY_InsertGlobal(char *name, symbolType_t type); -symbolNode_t *SY_InsertGlobalUnique(char *name, symbolType_t type); -void SY_FreeLocals(void); -void SY_FreeGlobals(void); -void SY_FreeConstants(int depth); -void SY_ClearShared(void); - -// PUBLIC DATA DECLARATIONS ------------------------------------------------ - -#endif + +//************************************************************************** +//** +//** symbol.h +//** +//************************************************************************** + +#ifndef __SYMBOL_H__ +#define __SYMBOL_H__ + +// HEADER FILES ------------------------------------------------------------ + +#include "common.h" +#include "pcode.h" + +// MACROS ------------------------------------------------------------------ + +#define MAX_ARRAY_DIMS 8 + +// TYPES ------------------------------------------------------------------- + +typedef enum +{ + SY_DUMMY, + SY_LABEL, + SY_SCRIPTVAR, + SY_SCRIPTALIAS, + SY_MAPVAR, + SY_WORLDVAR, + SY_GLOBALVAR, + SY_SCRIPTARRAY, + SY_MAPARRAY, + SY_WORLDARRAY, + SY_GLOBALARRAY, + SY_SPECIAL, + SY_CONSTANT, + SY_INTERNFUNC, + SY_SCRIPTFUNC +} symbolType_t; + +typedef struct +{ + U_BYTE index; +} symVar_t; + +typedef struct +{ + U_BYTE index; + int dimensions[MAX_ARRAY_DIMS]; + int ndim; + int size; +} symArray_t; + +typedef struct +{ + int address; +} symLabel_t; + +typedef struct +{ + int value; + int argCount; +} symSpecial_t; + +typedef struct +{ + int value; + char *strValue; + int fileDepth; +} symConstant_t; + +typedef struct +{ + pcd_t directCommand; + pcd_t stackCommand; + int argCount; + int optMask; + int outMask; + boolean hasReturnValue; + boolean latent; +} symInternFunc_t; + +typedef struct +{ + int address; + int argCount; + int varCount; + int funcNumber; + boolean hasReturnValue; + int sourceLine; + char *sourceName; + boolean predefined; +} symScriptFunc_t; + +typedef struct symbolNode_s +{ + struct symbolNode_s *left; + struct symbolNode_s *right; + char *name; + symbolType_t type; + boolean unused; + boolean imported; + union + { + symVar_t var; + symArray_t array; + symLabel_t label; + symSpecial_t special; + symConstant_t constant; + symInternFunc_t internFunc; + symScriptFunc_t scriptFunc; + } info; +} symbolNode_t; + +// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- + +void SY_Init(void); +symbolNode_t *SY_Find(char *name); +symbolNode_t *SY_FindLocal(char *name); +symbolNode_t *SY_FindGlobal(char *name); +symbolNode_t *SY_InsertLocal(char *name, symbolType_t type); +symbolNode_t *SY_InsertGlobal(char *name, symbolType_t type); +symbolNode_t *SY_InsertGlobalUnique(char *name, symbolType_t type); +void SY_FreeLocals(void); +void SY_FreeGlobals(void); +void SY_FreeConstants(int depth); +void SY_ClearShared(void); + +// PUBLIC DATA DECLARATIONS ------------------------------------------------ + +#endif diff --git a/token.c b/token.c index ac1d341..c8613c8 100644 --- a/token.c +++ b/token.c @@ -1,1586 +1,1586 @@ - -//************************************************************************** -//** -//** token.c -//** -//************************************************************************** - -// HEADER FILES ------------------------------------------------------------ - -#if defined(_WIN32) && !defined(_MSC_VER) -#define WIN32_LEAN_AND_MEAN -#include -#endif - -#ifdef __NeXT__ -#include -#else -#if !defined(unix) && !defined(__APPLE__) -#include -#endif -#include -#include -#include -#endif -#include -#include -#include -#include "common.h" -#include "token.h" -#include "error.h" -#include "misc.h" -#include "symbol.h" -#include "parse.h" - -// MACROS ------------------------------------------------------------------ - -#define NON_HEX_DIGIT 255 -#define MAX_NESTED_SOURCES 16 - -// TYPES ------------------------------------------------------------------- - -typedef enum -{ - CHR_EOF, - CHR_LETTER, - CHR_NUMBER, - CHR_QUOTE, - CHR_SPECIAL -} chr_t; - -typedef struct -{ - char *name; - char *start; - char *end; - char *position; - int line; - boolean incLineNumber; - boolean imported; - enum ImportModes prevMode; - char lastChar; -} nestInfo_t; - -// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- - -// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- - -// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- - -static int SortKeywords(const void *a, const void *b); -static void SetLocalIncludePath(char *sourceName); -static int PopNestedSource(enum ImportModes *prevMode); -static void ProcessLetterToken(void); -static void ProcessNumberToken(void); -static void EvalFixedConstant(int whole); -static void EvalHexConstant(void); -static void EvalRadixConstant(void); -static int DigitValue(char digit, int radix); -static void ProcessQuoteToken(void); -static void ProcessSpecialToken(void); -static boolean CheckForKeyword(void); -static boolean CheckForLineSpecial(void); -static boolean CheckForConstant(void); -static void NextChr(void); -static void SkipComment(void); -static void SkipCPPComment(void); -static void BumpMasterSourceLine(char Chr, boolean clear); // master line - Ty 07jan2000 -static char *AddFileName(const char *name); -static int OctalChar(); - -// EXTERNAL DATA DECLARATIONS ---------------------------------------------- - -// PUBLIC DATA DEFINITIONS ------------------------------------------------- - -tokenType_t tk_Token; -int tk_Line; -int tk_Number; -char *tk_String; -int tk_SpecialValue; -int tk_SpecialArgCount; -char *tk_SourceName; -int tk_IncludedLines; -boolean forSemicolonHack; -char MasterSourceLine[MAX_STATEMENT_LENGTH+1]; // master line - Ty 07jan2000 -int MasterSourcePos; // master position - Ty 07jan2000 -int PrevMasterSourcePos; // previous master position - RH 09feb2000 -boolean ClearMasterSourceLine; // master clear flag - Ty 07jan2000 - -// PRIVATE DATA DEFINITIONS ------------------------------------------------ - -static char Chr; -static char *FileStart; -static char *FilePtr; -static char *FileEnd; -static boolean SourceOpen; -static char ASCIIToChrCode[256]; -static byte ASCIIToHexDigit[256]; -static char TokenStringBuffer[MAX_QUOTED_LENGTH]; -static nestInfo_t OpenFiles[MAX_NESTED_SOURCES]; -static boolean AlreadyGot; -static int NestDepth; -static boolean IncLineNumber; -static char *FileNames; -static size_t FileNamesLen, FileNamesMax; - -// Pascal 12/11/08 -// Include paths. Lowest is searched first. -// Include path 0 is always set to the directory of the file being parsed. -static char IncludePaths[MAX_INCLUDE_PATHS][MAX_FILE_NAME_LENGTH]; -static int NumIncludePaths; - -static struct keyword_s -{ - char *name; - tokenType_t token; -} Keywords[] = -{ - { "break", TK_BREAK }, - { "case", TK_CASE }, - { "const", TK_CONST }, - { "continue", TK_CONTINUE }, - { "default", TK_DEFAULT }, - { "define", TK_DEFINE }, - { "do", TK_DO }, - { "else", TK_ELSE }, - { "for", TK_FOR }, - { "goto", TK_GOTO }, - { "if", TK_IF }, - { "include", TK_INCLUDE }, - { "int", TK_INT }, - { "open", TK_OPEN }, - { "print", TK_PRINT }, - { "printbold", TK_PRINTBOLD }, - { "log", TK_LOG }, - { "hudmessage", TK_HUDMESSAGE }, - { "hudmessagebold", TK_HUDMESSAGEBOLD }, - { "restart", TK_RESTART }, - { "script", TK_SCRIPT }, - { "special", TK_SPECIAL }, - { "str", TK_STR }, - { "suspend", TK_SUSPEND }, - { "switch", TK_SWITCH }, - { "terminate", TK_TERMINATE }, - { "until", TK_UNTIL }, - { "void", TK_VOID }, - { "while", TK_WHILE }, - { "world", TK_WORLD }, - { "global", TK_GLOBAL }, - // [BC] Start Skulltag tokens. - { "respawn", TK_RESPAWN }, - { "death", TK_DEATH }, - { "enter", TK_ENTER }, - { "pickup", TK_PICKUP }, - { "bluereturn", TK_BLUERETURN }, - { "redreturn", TK_REDRETURN }, - { "whitereturn", TK_WHITERETURN }, - // [BC] End Skulltag tokens. - { "nocompact", TK_NOCOMPACT }, - { "lightning", TK_LIGHTNING }, - { "createtranslation", TK_CREATETRANSLATION }, - { "function", TK_FUNCTION }, - { "return", TK_RETURN }, - { "wadauthor", TK_WADAUTHOR }, - { "nowadauthor", TK_NOWADAUTHOR }, - { "acs_executewait", TK_ACSEXECUTEWAIT }, - { "acs_namedexecutewait", TK_ACSNAMEDEXECUTEWAIT }, - { "encryptstrings", TK_ENCRYPTSTRINGS }, - { "import", TK_IMPORT }, - { "library", TK_LIBRARY }, - { "libdefine", TK_LIBDEFINE }, - { "bool", TK_BOOL }, - { "net", TK_NET }, - { "clientside", TK_CLIENTSIDE }, // [BB] - { "disconnect", TK_DISCONNECT }, - { "event", TK_EVENT }, //[BB] - { "unloading", TK_UNLOADING }, - { "static", TK_STATIC }, - { "strparam", TK_STRPARAM_EVAL }, // [FDARI] - { "strcpy", TK_STRCPY }, // [FDARI] - { "region", TK_REGION }, // [mxd] - { "endregion", TK_ENDREGION }, // [mxd] - { "kill", TK_KILL }, // [JM] - { "reopen", TK_REOPEN }, // [Nash] - { "morphactor", TK_MORPHACTOR }, // [Dasperal] -}; - -#define NUM_KEYWORDS (sizeof(Keywords)/sizeof(Keywords[0])) - -// CODE -------------------------------------------------------------------- - -//========================================================================== -// -// TK_Init -// -//========================================================================== - -void TK_Init(void) -{ - int i; - - for(i = 0; i < 256; i++) - { - ASCIIToChrCode[i] = CHR_SPECIAL; - ASCIIToHexDigit[i] = NON_HEX_DIGIT; - } - for(i = '0'; i <= '9'; i++) - { - ASCIIToChrCode[i] = CHR_NUMBER; - ASCIIToHexDigit[i] = i-'0'; - } - for(i = 'A'; i <= 'F'; i++) - { - ASCIIToHexDigit[i] = 10+(i-'A'); - } - for(i = 'a'; i <= 'f'; i++) - { - ASCIIToHexDigit[i] = 10+(i-'a'); - } - for(i = 'A'; i <= 'Z'; i++) - { - ASCIIToChrCode[i] = CHR_LETTER; - } - for(i = 'a'; i <= 'z'; i++) - { - ASCIIToChrCode[i] = CHR_LETTER; - } - ASCIIToChrCode[ASCII_QUOTE] = CHR_QUOTE; - ASCIIToChrCode[ASCII_UNDERSCORE] = CHR_LETTER; - ASCIIToChrCode[EOF_CHARACTER] = CHR_EOF; - tk_String = TokenStringBuffer; - IncLineNumber = FALSE; - tk_IncludedLines = 0; - NumIncludePaths = 1; // the first path is always the parsed file path - Pascal 12/11/08 - SourceOpen = FALSE; - *MasterSourceLine = '\0'; // master line - Ty 07jan2000 - MasterSourcePos = 0; // master position - Ty 07jan2000 - ClearMasterSourceLine = TRUE; // clear the line to start - qsort (Keywords, NUM_KEYWORDS, sizeof(Keywords[0]), SortKeywords); - FileNames = MS_Alloc(4096, ERR_OUT_OF_MEMORY); - FileNamesLen = 0; - FileNamesMax = 4096; -} - -//========================================================================== -// -// SortKeywords -// -//========================================================================== - -static int SortKeywords(const void *a, const void *b) -{ - return strcmp (((struct keyword_s *)a)->name, - ((struct keyword_s *)b)->name); -} - -//========================================================================== -// -// TK_OpenSource -// -//========================================================================== - -void TK_OpenSource(char *fileName) -{ - int size; - - TK_CloseSource(); - size = MS_LoadFile(fileName, &FileStart); - tk_SourceName = AddFileName(fileName); - SetLocalIncludePath(fileName); - SourceOpen = TRUE; - FileEnd = FileStart+size; - FilePtr = FileStart; - tk_Line = 1; - tk_Token = TK_NONE; - AlreadyGot = FALSE; - NestDepth = 0; - NextChr(); -} - -//========================================================================== -// -// AddFileName -// -//========================================================================== - -static char *AddFileName(const char *name) -{ - size_t len = strlen(name) + 1; - char *namespot; - - if (FileNamesLen + len > FileNamesMax) - { - FileNames = MS_Alloc(FileNamesMax, ERR_OUT_OF_MEMORY); - FileNamesLen = 0; - } - namespot = FileNames + FileNamesLen; - memcpy(namespot, name, len); - FileNamesLen += len; - return namespot; -} - -//========================================================================== -// -// TK_AddIncludePath -// This adds an include path with less priority than the ones already added -// -// Pascal 12/11/08 -// -//========================================================================== - -void TK_AddIncludePath(char *sourcePath) -{ - if(NumIncludePaths < MAX_INCLUDE_PATHS) - { - // Add to list - strcpy(IncludePaths[NumIncludePaths], sourcePath); - - // Not ending with directory delimiter? - if(!MS_IsDirectoryDelimiter(*(IncludePaths[NumIncludePaths] + strlen(IncludePaths[NumIncludePaths]) - 1))) - { - // Add a directory delimiter to the include path - strcat(IncludePaths[NumIncludePaths], "/"); - } - MS_Message(MSG_DEBUG, "Add include path %d: \"%s\"\n", NumIncludePaths, IncludePaths[NumIncludePaths]); - NumIncludePaths++; - } -} - -//========================================================================== -// -// TK_AddProgramIncludePath -// Adds an include path for the directory of the executable. -// -//========================================================================== - -void TK_AddProgramIncludePath(char *progname) -{ - if(NumIncludePaths < MAX_INCLUDE_PATHS) - { -#ifdef _WIN32 -#ifdef _MSC_VER -#if _MSC_VER >= 1300 - if (_get_pgmptr(&progname) != 0) - { - return; - } -#else - progname = _pgmptr; -#endif -#else - char progbuff[1024]; - GetModuleFileName(0, progbuff, sizeof(progbuff)); - progbuff[sizeof(progbuff)-1] = '\0'; - progname = progbuff; -#endif -#else - char progbuff[PATH_MAX]; - if (realpath(progname, progbuff) != NULL) - { - progname = progbuff; - } -#endif - strcpy(IncludePaths[NumIncludePaths], progname); - if(MS_StripFilename(IncludePaths[NumIncludePaths])) - { - MS_Message(MSG_DEBUG, "Program include path is %d: \"%s\"\n", NumIncludePaths, IncludePaths[NumIncludePaths]); - NumIncludePaths++; - } - } -} - -//========================================================================== -// -// SetLocalIncludePath -// This sets the first include path -// -// Pascal 12/11/08 -// -//========================================================================== - -static void SetLocalIncludePath(char *sourceName) -{ - strcpy(IncludePaths[0], sourceName); - if(MS_StripFilename(IncludePaths[0]) == NO) - { - IncludePaths[0][0] = 0; - } -} - - -//========================================================================== -// -// TK_Include -// -//========================================================================== - -void TK_Include(char *fileName) -{ - char sourceName[MAX_FILE_NAME_LENGTH]; - int size, i; - nestInfo_t *info; - boolean foundfile = FALSE; - - MS_Message(MSG_DEBUG, "*Including %s\n", fileName); - if(NestDepth == MAX_NESTED_SOURCES) - { - ERR_Exit(ERR_INCL_NESTING_TOO_DEEP, YES, fileName); - } - info = &OpenFiles[NestDepth++]; - info->name = tk_SourceName; - info->start = FileStart; - info->end = FileEnd; - info->position = FilePtr; - info->line = tk_Line; - info->incLineNumber = IncLineNumber; - info->lastChar = Chr; - info->imported = NO; - - // Pascal 30/11/08 - // Handle absolute paths - if(MS_IsPathAbsolute(fileName)) - { -#if defined(_WIN32) || defined(__MSDOS__) - sourceName[0] = '\0'; - if(MS_IsDirectoryDelimiter(fileName[0])) - { - // The source file is absolute for the drive, but does not - // specify a drive. Use the path for the current file to - // get the drive letter, if it has one. - if(IncludePaths[0][0] != '\0' && IncludePaths[0][1] == ':') - { - sourceName[0] = IncludePaths[0][0]; - sourceName[1] = ':'; - sourceName[2] = '\0'; - } - } - strcat(sourceName, fileName); -#else - strcpy(sourceName, fileName); -#endif - foundfile = MS_FileExists(sourceName); - } - else - { - // Pascal 12/11/08 - // Find the file in the include paths - for(i = 0; i < NumIncludePaths; i++) - { - strcpy(sourceName, IncludePaths[i]); - strcat(sourceName, fileName); - if(MS_FileExists(sourceName)) - { - foundfile = TRUE; - break; - } - } - } - - if(!foundfile) - { - ERR_ErrorAt(tk_SourceName, tk_Line); - ERR_Exit(ERR_CANT_FIND_INCLUDE, YES, fileName, tk_SourceName, tk_Line); - } - - MS_Message(MSG_DEBUG, "*Include file found at %s\n", sourceName); - - // Now change the first include path to the file directory - SetLocalIncludePath(sourceName); - - tk_SourceName = AddFileName(sourceName); - size = MS_LoadFile(tk_SourceName, &FileStart); - FileEnd = FileStart+size; - FilePtr = FileStart; - tk_Line = 1; - IncLineNumber = FALSE; - tk_Token = TK_NONE; - AlreadyGot = FALSE; - BumpMasterSourceLine('x',TRUE); // dummy x - NextChr(); -} - -//========================================================================== -// -// TK_Import -// -//========================================================================== - -void TK_Import(char *fileName, enum ImportModes prevMode) -{ - TK_Include (fileName); - OpenFiles[NestDepth - 1].imported = YES; - OpenFiles[NestDepth - 1].prevMode = prevMode; - ImportMode = IMPORT_Importing; -} - -//========================================================================== -// -// PopNestedSource -// -//========================================================================== - -static int PopNestedSource(enum ImportModes *prevMode) -{ - nestInfo_t *info; - - MS_Message(MSG_DEBUG, "*Leaving %s\n", tk_SourceName); - free(FileStart); - SY_FreeConstants(NestDepth); - tk_IncludedLines += tk_Line; - info = &OpenFiles[--NestDepth]; - tk_SourceName = info->name; - FileStart = info->start; - FileEnd = info->end; - FilePtr = info->position; - tk_Line = info->line; - IncLineNumber = info->incLineNumber; - Chr = info->lastChar; - tk_Token = TK_NONE; - AlreadyGot = FALSE; - - // Pascal 12/11/08 - // Set the first include path back to this file directory - SetLocalIncludePath(tk_SourceName); - - *prevMode = info->prevMode; - return info->imported ? 2 : 0; -} - -//========================================================================== -// -// TK_CloseSource -// -//========================================================================== - -void TK_CloseSource(void) -{ - int i; - - if(SourceOpen) - { - free(FileStart); - for(i = 0; i < NestDepth; i++) - { - free(OpenFiles[i].start); - } - SourceOpen = FALSE; - } -} - -//========================================================================== -// -// TK_GetDepth -// -//========================================================================== - -int TK_GetDepth(void) -{ - return NestDepth; -} - -//========================================================================== -// -// TK_NextToken -// -//========================================================================== - -tokenType_t TK_NextToken(void) -{ - enum ImportModes prevMode; - boolean validToken; - - if(AlreadyGot == TRUE) - { - int t = MasterSourcePos; - MasterSourcePos = PrevMasterSourcePos; - PrevMasterSourcePos = t; - AlreadyGot = FALSE; - return tk_Token; - } - tk_String = TokenStringBuffer; - validToken = NO; - PrevMasterSourcePos = MasterSourcePos; - do - { - while(Chr == ASCII_SPACE) - { - NextChr(); - } - switch(ASCIIToChrCode[(byte)Chr]) - { - case CHR_EOF: - tk_Token = TK_EOF; - break; - case CHR_LETTER: - ProcessLetterToken(); - break; - case CHR_NUMBER: - ProcessNumberToken(); - break; - case CHR_QUOTE: - ProcessQuoteToken(); - break; - default: - ProcessSpecialToken(); - break; - } - if(tk_Token == TK_STARTCOMMENT) - { - SkipComment(); - } - else if(tk_Token == TK_CPPCOMMENT) - { - SkipCPPComment(); - } - else if((tk_Token == TK_EOF) && (NestDepth > 0)) - { - if (PopNestedSource(&prevMode)) - { - ImportMode = prevMode; - if(!ExporterFlagged) - { - ERR_Exit(ERR_EXPORTER_NOT_FLAGGED, YES, NULL); - } - SY_ClearShared(); - } - } - else - { - validToken = YES; - } - } while(validToken == NO); - return tk_Token; -} - -//========================================================================== -// -// TK_NextCharacter -// -//========================================================================== - -int TK_NextCharacter(void) -{ - int c; - - while(Chr == ASCII_SPACE) - { - NextChr(); - } - c = (int)Chr; - if(c == EOF_CHARACTER) - { - c = -1; - } - NextChr(); - return c; -} - -//========================================================================== -// -// TK_SkipPast -// -//========================================================================== - -void TK_SkipPast(tokenType_t token) -{ - while (tk_Token != token && tk_Token != TK_EOF) - { - TK_NextToken(); - } - TK_NextToken(); -} - -//========================================================================== -// -// TK_SkipTo -// -//========================================================================== - -void TK_SkipTo(tokenType_t token) -{ - while (tk_Token != token && tk_Token != TK_EOF) - { - TK_NextToken(); - } -} - -//========================================================================== -// -// TK_NextTokenMustBe -// -//========================================================================== - -boolean TK_NextTokenMustBe(tokenType_t token, error_t error) -{ - if(TK_NextToken() != token) - { - ERR_Error(error, YES); - /* - if(skipToken == TK_EOF) - { - ERR_Finish(); - } - else if(skipToken != TK_NONE) - { - TK_SkipPast(skipToken); - } - return NO; - */ - ERR_Finish(); - } - return YES; -} - -//========================================================================== -// -// TK_TokenMustBe -// -//========================================================================== - -boolean TK_TokenMustBe(tokenType_t token, error_t error) -{ - if (token == TK_SEMICOLON && forSemicolonHack) - { - token = TK_RPAREN; - } - if(tk_Token != token) - { - ERR_Error(error, YES); - /* - if(skipToken == TK_EOF) - { - ERR_Finish(); - } - else if(skipToken != TK_NONE) - { - while(tk_Token != skipToken) - { - TK_NextToken(); - } - } - return NO; - */ - ERR_Finish(); - } - return YES; -} - -//========================================================================== -// -// TK_Member -// -//========================================================================== - -boolean TK_Member(tokenType_t *list) -{ - int i; - - for(i = 0; list[i] != TK_NONE; i++) - { - if(tk_Token == list[i]) - { - return YES; - } - } - return NO; -} - -//========================================================================== -// -// TK_Undo -// -//========================================================================== - -void TK_Undo(void) -{ - if(tk_Token != TK_NONE) - { - if (AlreadyGot == FALSE) - { - int t = MasterSourcePos; - MasterSourcePos = PrevMasterSourcePos; - PrevMasterSourcePos = t; - AlreadyGot = TRUE; - } - } -} - -//========================================================================== -// -// ProcessLetterToken -// -//========================================================================== - -static void ProcessLetterToken(void) -{ - int i; - char *text; - - i = 0; - text = TokenStringBuffer; - while (ASCIIToChrCode[(byte)Chr] == CHR_LETTER - || ASCIIToChrCode[(byte)Chr] == CHR_NUMBER) - { - if(++i == MAX_IDENTIFIER_LENGTH) - { - ERR_Error(ERR_IDENTIFIER_TOO_LONG, YES); - } - if(i < MAX_IDENTIFIER_LENGTH) - { - *text++ = Chr; - } - NextChr(); - } - *text = 0; - MS_StrLwr(TokenStringBuffer); - if(CheckForKeyword() == FALSE - && CheckForLineSpecial() == FALSE - && CheckForConstant() == FALSE) - { - tk_Token = TK_IDENTIFIER; - } -} - -//========================================================================== -// -// CheckForKeyword -// -//========================================================================== - -static boolean CheckForKeyword(void) -{ - int min, max, probe, lexx; - - // [RH] Use a binary search - min = 0; - max = NUM_KEYWORDS-1; - probe = NUM_KEYWORDS/2; - - while (max - min >= 0) - { - lexx = strcmp(tk_String, Keywords[probe].name); - if(lexx == 0) - { - tk_Token = Keywords[probe].token; - return TRUE; - } - else if(lexx < 0) - { - max = probe-1; - } - else - { - min = probe+1; - } - probe = (max-min)/2+min; - } - return FALSE; -} - -//========================================================================== -// -// CheckForLineSpecial -// -//========================================================================== - -static boolean CheckForLineSpecial(void) -{ - symbolNode_t *sym; - - sym = SY_FindGlobal(tk_String); - if(sym == NULL) - { - return FALSE; - } - if(sym->type != SY_SPECIAL) - { - return FALSE; - } - tk_Token = TK_LINESPECIAL; - tk_SpecialValue = sym->info.special.value; - tk_SpecialArgCount = sym->info.special.argCount; - return TRUE; -} - -//========================================================================== -// -// CheckForConstant -// -//========================================================================== - -static boolean CheckForConstant(void) -{ - symbolNode_t *sym; - - sym = SY_FindGlobal(tk_String); - if(sym == NULL) - { - return FALSE; - } - if(sym->type != SY_CONSTANT) - { - return FALSE; - } - if(sym->info.constant.strValue != NULL) - { - MS_Message(MSG_DEBUG, "Constant string: %s\n", sym->info.constant.strValue); - tk_Token = TK_STRING; - tk_String = sym->info.constant.strValue; - } - else - { - tk_Token = TK_NUMBER; - tk_Number = sym->info.constant.value; - } - return TRUE; -} - -//========================================================================== -// -// ProcessNumberToken -// -//========================================================================== - -static void ProcessNumberToken(void) -{ - char c; - - c = Chr; - NextChr(); - if(c == '0' && (Chr == 'x' || Chr == 'X')) - { // Hexadecimal constant - NextChr(); - EvalHexConstant(); - return; - } - tk_Number = c-'0'; - while(ASCIIToChrCode[(byte)Chr] == CHR_NUMBER) - { - tk_Number = 10*tk_Number+(Chr-'0'); - NextChr(); - } - if(Chr == '.') - { // Fixed point - NextChr(); // Skip period - EvalFixedConstant(tk_Number); - return; - } - if(Chr == ASCII_UNDERSCORE) - { - NextChr(); // Skip underscore - EvalRadixConstant(); - return; - } - tk_Token = TK_NUMBER; -} - -//========================================================================== -// -// EvalFixedConstant -// -//========================================================================== - -static void EvalFixedConstant(int whole) -{ - double frac; - double divisor; - - frac = 0; - divisor = 1; - while(ASCIIToChrCode[(byte)Chr] == CHR_NUMBER) - { - frac = 10*frac+(Chr-'0'); - divisor *= 10; - NextChr(); - } - tk_Number = (whole<<16)+(int)(65536.0*frac/divisor); - tk_Token = TK_NUMBER; -} - -//========================================================================== -// -// EvalHexConstant -// -//========================================================================== - -static void EvalHexConstant(void) -{ - tk_Number = 0; - while(ASCIIToHexDigit[(byte)Chr] != NON_HEX_DIGIT) - { - tk_Number = (tk_Number<<4)+ASCIIToHexDigit[(byte)Chr]; - NextChr(); - } - tk_Token = TK_NUMBER; -} - -//========================================================================== -// -// EvalRadixConstant -// -//========================================================================== - -static void EvalRadixConstant(void) -{ - int radix; - int digitVal; - - radix = tk_Number; - if(radix < 2 || radix > 36) - { - ERR_Error(ERR_BAD_RADIX_CONSTANT, YES, NULL); - radix = 36; - } - tk_Number = 0; - while((digitVal = DigitValue(Chr, radix)) != -1) - { - tk_Number = radix*tk_Number+digitVal; - NextChr(); - } - tk_Token = TK_NUMBER; -} - -//========================================================================== -// -// DigitValue -// -// Returns -1 if the digit is not allowed in the specified radix. -// -//========================================================================== - -static int DigitValue(char digit, int radix) -{ - digit = toupper(digit); - if(digit < '0' || (digit > '9' && digit < 'A') || digit > 'Z') - { - return -1; - } - if(digit > '9') - { - digit = 10+digit-'A'; - } - else - { - digit -= '0'; - } - if(digit >= radix) - { - return -1; - } - return digit; -} - -//========================================================================== -// -// ProcessQuoteToken -// -//========================================================================== - -static void ProcessQuoteToken(void) -{ - int i; - char *text; - boolean escaped; - - i = 0; - escaped = FALSE; - text = TokenStringBuffer; - NextChr(); - while(Chr != EOF_CHARACTER) - { - if(Chr == ASCII_QUOTE && escaped == 0) // [JB] - { - break; - } - if(++i == MAX_QUOTED_LENGTH) - { - ERR_Error(ERR_STRING_TOO_LONG, YES, NULL); - } - if(i < MAX_QUOTED_LENGTH) - { - *text++ = Chr; - } - // escape the character after a backslash [JB] - if(Chr == '\\') - escaped ^= (Chr == '\\'); - else - escaped = FALSE; - NextChr(); - } - *text = 0; - if(Chr == ASCII_QUOTE) - { - NextChr(); - } - tk_Token = TK_STRING; -} - -//========================================================================== -// -// ProcessSpecialToken -// -//========================================================================== - -static void ProcessSpecialToken(void) -{ - char c; - - c = Chr; - NextChr(); - switch(c) - { - case '+': - switch(Chr) - { - case '=': - tk_Token = TK_ADDASSIGN; - NextChr(); - break; - case '+': - tk_Token = TK_INC; - NextChr(); - break; - default: - tk_Token = TK_PLUS; - break; - } - break; - case '-': - switch(Chr) - { - case '=': - tk_Token = TK_SUBASSIGN; - NextChr(); - break; - case '-': - tk_Token = TK_DEC; - NextChr(); - break; - default: - tk_Token = TK_MINUS; - break; - } - break; - case '*': - switch(Chr) - { - case '=': - tk_Token = TK_MULASSIGN; - NextChr(); - break; - case '/': - tk_Token = TK_ENDCOMMENT; - NextChr(); - break; - default: - tk_Token = TK_ASTERISK; - break; - } - break; - case '/': - switch(Chr) - { - case '=': - tk_Token = TK_DIVASSIGN; - NextChr(); - break; - case '/': - tk_Token = TK_CPPCOMMENT; - break; - case '*': - tk_Token = TK_STARTCOMMENT; - NextChr(); - break; - default: - tk_Token = TK_SLASH; - break; - } - break; - case '%': - if(Chr == '=') - { - tk_Token = TK_MODASSIGN; - NextChr(); - } - else - { - tk_Token = TK_PERCENT; - } - break; - case '=': - if(Chr == '=') - { - tk_Token = TK_EQ; - NextChr(); - } - else - { - tk_Token = TK_ASSIGN; - } - break; - case '<': - if(Chr == '=') - { - tk_Token = TK_LE; - NextChr(); - } - else if(Chr == '<') - { - NextChr(); - if(Chr == '=') - { - tk_Token = TK_LSASSIGN; - NextChr(); - } - else - { - tk_Token = TK_LSHIFT; - } - - } - else - { - tk_Token = TK_LT; - } - break; - case '>': - if(Chr == '=') - { - tk_Token = TK_GE; - NextChr(); - } - else if(Chr == '>') - { - NextChr(); - if(Chr == '=') - { - tk_Token = TK_RSASSIGN; - NextChr(); - } - else - { - tk_Token = TK_RSHIFT; - } - } - else - { - tk_Token = TK_GT; - } - break; - case '!': - if(Chr == '=') - { - tk_Token = TK_NE; - NextChr(); - } - else - { - tk_Token = TK_NOT; - } - break; - case '&': - if(Chr == '&') - { - tk_Token = TK_ANDLOGICAL; - NextChr(); - } - else if(Chr == '=') - { - tk_Token = TK_ANDASSIGN; - NextChr(); - } - else - { - tk_Token = TK_ANDBITWISE; - } - break; - case '|': - if(Chr == '|') - { - tk_Token = TK_ORLOGICAL; - NextChr(); - } - else if(Chr == '=') - { - tk_Token = TK_ORASSIGN; - NextChr(); - } - else - { - tk_Token = TK_ORBITWISE; - } - break; - case '(': - tk_Token = TK_LPAREN; - break; - case ')': - tk_Token = TK_RPAREN; - break; - case '{': - tk_Token = TK_LBRACE; - break; - case '}': - tk_Token = TK_RBRACE; - break; - case '[': - tk_Token = TK_LBRACKET; - break; - case ']': - tk_Token = TK_RBRACKET; - break; - case '?': - tk_Token = TK_TERNARY; - break; - case ':': - tk_Token = TK_COLON; - break; - case ';': - tk_Token = TK_SEMICOLON; - break; - case ',': - tk_Token = TK_COMMA; - break; - case '.': - tk_Token = TK_PERIOD; - break; - case '#': - tk_Token = TK_NUMBERSIGN; - break; - case '@': - tk_Token = TK_ATSIGN; - break; - case '^': - if(Chr == '=') - { - tk_Token = TK_EORASSIGN; - NextChr(); - } - else - { - tk_Token = TK_EORBITWISE; - } - break; - case '~': - tk_Token = TK_TILDE; - break; - case '\'': - if(Chr == '\\') - { - NextChr(); - switch(Chr) - { - case '0': case '1': case '2': case '3': - case '4': case '5': case '6': case '7': - tk_Number = OctalChar(); - break; - case 'x': case 'X': - NextChr(); - EvalHexConstant(); - if(Chr != '\'') - { - ERR_Exit(ERR_BAD_CHARACTER_CONSTANT, YES, NULL); - } - NextChr(); - break; - case 'a': - tk_Number = '\a'; - break; - case 'b': - tk_Number = '\b'; - break; - case 't': - tk_Number = '\t'; - break; - case 'v': - tk_Number = '\v'; - break; - case 'n': - tk_Number = '\n'; - break; - case 'f': - tk_Number = '\f'; - break; - case 'r': - tk_Number = '\r'; - break; - case '\'': - case '\\': - tk_Number = Chr; - break; - default: - ERR_Exit(ERR_BAD_CHARACTER_CONSTANT, YES, NULL); - } - tk_Token = TK_NUMBER; - } - else if(Chr == '\'') - { - ERR_Exit(ERR_BAD_CHARACTER_CONSTANT, YES, NULL); - } - else - { - tk_Number = Chr; - tk_Token = TK_NUMBER; - } - NextChr(); - if(Chr != '\'') - { - ERR_Exit(ERR_BAD_CHARACTER_CONSTANT, YES, NULL); - } - NextChr(); - break; - default: - ERR_Exit(ERR_BAD_CHARACTER, YES, NULL); - break; - } -} - -//========================================================================== -// -// NextChr -// -//========================================================================== - -static void NextChr(void) -{ - if(FilePtr >= FileEnd) - { - Chr = EOF_CHARACTER; - return; - } - if(IncLineNumber == TRUE) - { - tk_Line++; - IncLineNumber = FALSE; - BumpMasterSourceLine('x',TRUE); // dummy x - } - Chr = *FilePtr++; - if(Chr < ASCII_SPACE && Chr >= 0) // Allow high ASCII characters - { - if(Chr == '\n') - { - IncLineNumber = TRUE; - } - Chr = ASCII_SPACE; - } - BumpMasterSourceLine(Chr,FALSE); -} - -//========================================================================== -// -// PeekChr // [JB] -// -//========================================================================== - -static int PeekChr(void) -{ - char ch; - if(FilePtr >= FileEnd) - { - return EOF_CHARACTER; - } - ch = *FilePtr-1; - if(ch < ASCII_SPACE && ch >= 0) // Allow high ASCII characters - { - ch = ASCII_SPACE; - } - return ch; -} - -//========================================================================== -// -// OctalChar // [JB] -// -//========================================================================== - -static int OctalChar() -{ - int digits = 1; - int code = Chr - '0'; - while(digits < 4 && PeekChr() >= '0' && PeekChr() <= '7') - { - NextChr(); - code = (code << 3) + Chr - '0'; - } - return code; -} - -//========================================================================== -// -// SkipComment -// -//========================================================================== - -void SkipComment(void) -{ - boolean first; - - first = FALSE; - while(Chr != EOF_CHARACTER) - { - if(first == TRUE && Chr == '/') - { - break; - } - first = (Chr == '*'); - NextChr(); - } - NextChr(); -} - -//========================================================================== -// -// SkipCPPComment -// -//========================================================================== - -void SkipCPPComment(void) -{ - while(FilePtr < FileEnd) - { - if(*FilePtr++ == '\n') - { - tk_Line++; - BumpMasterSourceLine('x',TRUE); // dummy x - break; - } - } - NextChr(); -} - -//========================================================================== -// -// BumpMasterSourceLine -// -//========================================================================== - -void BumpMasterSourceLine(char Chr, boolean clear) // master line - Ty 07jan2000 -{ - if (ClearMasterSourceLine) // set to clear last time, clear now for first character - { - *MasterSourceLine = '\0'; - MasterSourcePos = 0; - ClearMasterSourceLine = FALSE; - } - if (clear) - { - ClearMasterSourceLine = TRUE; - } - else - { - if (MasterSourcePos < MAX_STATEMENT_LENGTH) - MasterSourceLine[MasterSourcePos++] = Chr; - } -} - -//========================================================================== -// -// TK_SkipLine -// -//========================================================================== - -void TK_SkipLine(void) -{ - char *sourcenow = tk_SourceName; - int linenow = tk_Line; - do TK_NextToken(); while (tk_Line == linenow && tk_SourceName == sourcenow && tk_Token != TK_EOF); -} + +//************************************************************************** +//** +//** token.c +//** +//************************************************************************** + +// HEADER FILES ------------------------------------------------------------ + +#if defined(_WIN32) && !defined(_MSC_VER) +#define WIN32_LEAN_AND_MEAN +#include +#endif + +#ifdef __NeXT__ +#include +#else +#if !defined(unix) && !defined(__APPLE__) +#include +#endif +#include +#include +#include +#endif +#include +#include +#include +#include "common.h" +#include "token.h" +#include "error.h" +#include "misc.h" +#include "symbol.h" +#include "parse.h" + +// MACROS ------------------------------------------------------------------ + +#define NON_HEX_DIGIT 255 +#define MAX_NESTED_SOURCES 16 + +// TYPES ------------------------------------------------------------------- + +typedef enum +{ + CHR_EOF, + CHR_LETTER, + CHR_NUMBER, + CHR_QUOTE, + CHR_SPECIAL +} chr_t; + +typedef struct +{ + char *name; + char *start; + char *end; + char *position; + int line; + boolean incLineNumber; + boolean imported; + enum ImportModes prevMode; + char lastChar; +} nestInfo_t; + +// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- + +// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- + +// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- + +static int SortKeywords(const void *a, const void *b); +static void SetLocalIncludePath(char *sourceName); +static int PopNestedSource(enum ImportModes *prevMode); +static void ProcessLetterToken(void); +static void ProcessNumberToken(void); +static void EvalFixedConstant(int whole); +static void EvalHexConstant(void); +static void EvalRadixConstant(void); +static int DigitValue(char digit, int radix); +static void ProcessQuoteToken(void); +static void ProcessSpecialToken(void); +static boolean CheckForKeyword(void); +static boolean CheckForLineSpecial(void); +static boolean CheckForConstant(void); +static void NextChr(void); +static void SkipComment(void); +static void SkipCPPComment(void); +static void BumpMasterSourceLine(char Chr, boolean clear); // master line - Ty 07jan2000 +static char *AddFileName(const char *name); +static int OctalChar(); + +// EXTERNAL DATA DECLARATIONS ---------------------------------------------- + +// PUBLIC DATA DEFINITIONS ------------------------------------------------- + +tokenType_t tk_Token; +int tk_Line; +int tk_Number; +char *tk_String; +int tk_SpecialValue; +int tk_SpecialArgCount; +char *tk_SourceName; +int tk_IncludedLines; +boolean forSemicolonHack; +char MasterSourceLine[MAX_STATEMENT_LENGTH+1]; // master line - Ty 07jan2000 +int MasterSourcePos; // master position - Ty 07jan2000 +int PrevMasterSourcePos; // previous master position - RH 09feb2000 +boolean ClearMasterSourceLine; // master clear flag - Ty 07jan2000 + +// PRIVATE DATA DEFINITIONS ------------------------------------------------ + +static char Chr; +static char *FileStart; +static char *FilePtr; +static char *FileEnd; +static boolean SourceOpen; +static char ASCIIToChrCode[256]; +static byte ASCIIToHexDigit[256]; +static char TokenStringBuffer[MAX_QUOTED_LENGTH]; +static nestInfo_t OpenFiles[MAX_NESTED_SOURCES]; +static boolean AlreadyGot; +static int NestDepth; +static boolean IncLineNumber; +static char *FileNames; +static size_t FileNamesLen, FileNamesMax; + +// Pascal 12/11/08 +// Include paths. Lowest is searched first. +// Include path 0 is always set to the directory of the file being parsed. +static char IncludePaths[MAX_INCLUDE_PATHS][MAX_FILE_NAME_LENGTH]; +static int NumIncludePaths; + +static struct keyword_s +{ + char *name; + tokenType_t token; +} Keywords[] = +{ + { "break", TK_BREAK }, + { "case", TK_CASE }, + { "const", TK_CONST }, + { "continue", TK_CONTINUE }, + { "default", TK_DEFAULT }, + { "define", TK_DEFINE }, + { "do", TK_DO }, + { "else", TK_ELSE }, + { "for", TK_FOR }, + { "goto", TK_GOTO }, + { "if", TK_IF }, + { "include", TK_INCLUDE }, + { "int", TK_INT }, + { "open", TK_OPEN }, + { "print", TK_PRINT }, + { "printbold", TK_PRINTBOLD }, + { "log", TK_LOG }, + { "hudmessage", TK_HUDMESSAGE }, + { "hudmessagebold", TK_HUDMESSAGEBOLD }, + { "restart", TK_RESTART }, + { "script", TK_SCRIPT }, + { "special", TK_SPECIAL }, + { "str", TK_STR }, + { "suspend", TK_SUSPEND }, + { "switch", TK_SWITCH }, + { "terminate", TK_TERMINATE }, + { "until", TK_UNTIL }, + { "void", TK_VOID }, + { "while", TK_WHILE }, + { "world", TK_WORLD }, + { "global", TK_GLOBAL }, + // [BC] Start Skulltag tokens. + { "respawn", TK_RESPAWN }, + { "death", TK_DEATH }, + { "enter", TK_ENTER }, + { "pickup", TK_PICKUP }, + { "bluereturn", TK_BLUERETURN }, + { "redreturn", TK_REDRETURN }, + { "whitereturn", TK_WHITERETURN }, + // [BC] End Skulltag tokens. + { "nocompact", TK_NOCOMPACT }, + { "lightning", TK_LIGHTNING }, + { "createtranslation", TK_CREATETRANSLATION }, + { "function", TK_FUNCTION }, + { "return", TK_RETURN }, + { "wadauthor", TK_WADAUTHOR }, + { "nowadauthor", TK_NOWADAUTHOR }, + { "acs_executewait", TK_ACSEXECUTEWAIT }, + { "acs_namedexecutewait", TK_ACSNAMEDEXECUTEWAIT }, + { "encryptstrings", TK_ENCRYPTSTRINGS }, + { "import", TK_IMPORT }, + { "library", TK_LIBRARY }, + { "libdefine", TK_LIBDEFINE }, + { "bool", TK_BOOL }, + { "net", TK_NET }, + { "clientside", TK_CLIENTSIDE }, // [BB] + { "disconnect", TK_DISCONNECT }, + { "event", TK_EVENT }, //[BB] + { "unloading", TK_UNLOADING }, + { "static", TK_STATIC }, + { "strparam", TK_STRPARAM_EVAL }, // [FDARI] + { "strcpy", TK_STRCPY }, // [FDARI] + { "region", TK_REGION }, // [mxd] + { "endregion", TK_ENDREGION }, // [mxd] + { "kill", TK_KILL }, // [JM] + { "reopen", TK_REOPEN }, // [Nash] + { "morphactor", TK_MORPHACTOR }, // [Dasperal] +}; + +#define NUM_KEYWORDS (sizeof(Keywords)/sizeof(Keywords[0])) + +// CODE -------------------------------------------------------------------- + +//========================================================================== +// +// TK_Init +// +//========================================================================== + +void TK_Init(void) +{ + int i; + + for(i = 0; i < 256; i++) + { + ASCIIToChrCode[i] = CHR_SPECIAL; + ASCIIToHexDigit[i] = NON_HEX_DIGIT; + } + for(i = '0'; i <= '9'; i++) + { + ASCIIToChrCode[i] = CHR_NUMBER; + ASCIIToHexDigit[i] = i-'0'; + } + for(i = 'A'; i <= 'F'; i++) + { + ASCIIToHexDigit[i] = 10+(i-'A'); + } + for(i = 'a'; i <= 'f'; i++) + { + ASCIIToHexDigit[i] = 10+(i-'a'); + } + for(i = 'A'; i <= 'Z'; i++) + { + ASCIIToChrCode[i] = CHR_LETTER; + } + for(i = 'a'; i <= 'z'; i++) + { + ASCIIToChrCode[i] = CHR_LETTER; + } + ASCIIToChrCode[ASCII_QUOTE] = CHR_QUOTE; + ASCIIToChrCode[ASCII_UNDERSCORE] = CHR_LETTER; + ASCIIToChrCode[EOF_CHARACTER] = CHR_EOF; + tk_String = TokenStringBuffer; + IncLineNumber = FALSE; + tk_IncludedLines = 0; + NumIncludePaths = 1; // the first path is always the parsed file path - Pascal 12/11/08 + SourceOpen = FALSE; + *MasterSourceLine = '\0'; // master line - Ty 07jan2000 + MasterSourcePos = 0; // master position - Ty 07jan2000 + ClearMasterSourceLine = TRUE; // clear the line to start + qsort (Keywords, NUM_KEYWORDS, sizeof(Keywords[0]), SortKeywords); + FileNames = MS_Alloc(4096, ERR_OUT_OF_MEMORY); + FileNamesLen = 0; + FileNamesMax = 4096; +} + +//========================================================================== +// +// SortKeywords +// +//========================================================================== + +static int SortKeywords(const void *a, const void *b) +{ + return strcmp (((struct keyword_s *)a)->name, + ((struct keyword_s *)b)->name); +} + +//========================================================================== +// +// TK_OpenSource +// +//========================================================================== + +void TK_OpenSource(char *fileName) +{ + int size; + + TK_CloseSource(); + size = MS_LoadFile(fileName, &FileStart); + tk_SourceName = AddFileName(fileName); + SetLocalIncludePath(fileName); + SourceOpen = TRUE; + FileEnd = FileStart+size; + FilePtr = FileStart; + tk_Line = 1; + tk_Token = TK_NONE; + AlreadyGot = FALSE; + NestDepth = 0; + NextChr(); +} + +//========================================================================== +// +// AddFileName +// +//========================================================================== + +static char *AddFileName(const char *name) +{ + size_t len = strlen(name) + 1; + char *namespot; + + if (FileNamesLen + len > FileNamesMax) + { + FileNames = MS_Alloc(FileNamesMax, ERR_OUT_OF_MEMORY); + FileNamesLen = 0; + } + namespot = FileNames + FileNamesLen; + memcpy(namespot, name, len); + FileNamesLen += len; + return namespot; +} + +//========================================================================== +// +// TK_AddIncludePath +// This adds an include path with less priority than the ones already added +// +// Pascal 12/11/08 +// +//========================================================================== + +void TK_AddIncludePath(char *sourcePath) +{ + if(NumIncludePaths < MAX_INCLUDE_PATHS) + { + // Add to list + strcpy(IncludePaths[NumIncludePaths], sourcePath); + + // Not ending with directory delimiter? + if(!MS_IsDirectoryDelimiter(*(IncludePaths[NumIncludePaths] + strlen(IncludePaths[NumIncludePaths]) - 1))) + { + // Add a directory delimiter to the include path + strcat(IncludePaths[NumIncludePaths], "/"); + } + MS_Message(MSG_DEBUG, "Add include path %d: \"%s\"\n", NumIncludePaths, IncludePaths[NumIncludePaths]); + NumIncludePaths++; + } +} + +//========================================================================== +// +// TK_AddProgramIncludePath +// Adds an include path for the directory of the executable. +// +//========================================================================== + +void TK_AddProgramIncludePath(char *progname) +{ + if(NumIncludePaths < MAX_INCLUDE_PATHS) + { +#ifdef _WIN32 +#ifdef _MSC_VER +#if _MSC_VER >= 1300 + if (_get_pgmptr(&progname) != 0) + { + return; + } +#else + progname = _pgmptr; +#endif +#else + char progbuff[1024]; + GetModuleFileName(0, progbuff, sizeof(progbuff)); + progbuff[sizeof(progbuff)-1] = '\0'; + progname = progbuff; +#endif +#else + char progbuff[PATH_MAX]; + if (realpath(progname, progbuff) != NULL) + { + progname = progbuff; + } +#endif + strcpy(IncludePaths[NumIncludePaths], progname); + if(MS_StripFilename(IncludePaths[NumIncludePaths])) + { + MS_Message(MSG_DEBUG, "Program include path is %d: \"%s\"\n", NumIncludePaths, IncludePaths[NumIncludePaths]); + NumIncludePaths++; + } + } +} + +//========================================================================== +// +// SetLocalIncludePath +// This sets the first include path +// +// Pascal 12/11/08 +// +//========================================================================== + +static void SetLocalIncludePath(char *sourceName) +{ + strcpy(IncludePaths[0], sourceName); + if(MS_StripFilename(IncludePaths[0]) == NO) + { + IncludePaths[0][0] = 0; + } +} + + +//========================================================================== +// +// TK_Include +// +//========================================================================== + +void TK_Include(char *fileName) +{ + char sourceName[MAX_FILE_NAME_LENGTH]; + int size, i; + nestInfo_t *info; + boolean foundfile = FALSE; + + MS_Message(MSG_DEBUG, "*Including %s\n", fileName); + if(NestDepth == MAX_NESTED_SOURCES) + { + ERR_Exit(ERR_INCL_NESTING_TOO_DEEP, YES, fileName); + } + info = &OpenFiles[NestDepth++]; + info->name = tk_SourceName; + info->start = FileStart; + info->end = FileEnd; + info->position = FilePtr; + info->line = tk_Line; + info->incLineNumber = IncLineNumber; + info->lastChar = Chr; + info->imported = NO; + + // Pascal 30/11/08 + // Handle absolute paths + if(MS_IsPathAbsolute(fileName)) + { +#if defined(_WIN32) || defined(__MSDOS__) + sourceName[0] = '\0'; + if(MS_IsDirectoryDelimiter(fileName[0])) + { + // The source file is absolute for the drive, but does not + // specify a drive. Use the path for the current file to + // get the drive letter, if it has one. + if(IncludePaths[0][0] != '\0' && IncludePaths[0][1] == ':') + { + sourceName[0] = IncludePaths[0][0]; + sourceName[1] = ':'; + sourceName[2] = '\0'; + } + } + strcat(sourceName, fileName); +#else + strcpy(sourceName, fileName); +#endif + foundfile = MS_FileExists(sourceName); + } + else + { + // Pascal 12/11/08 + // Find the file in the include paths + for(i = 0; i < NumIncludePaths; i++) + { + strcpy(sourceName, IncludePaths[i]); + strcat(sourceName, fileName); + if(MS_FileExists(sourceName)) + { + foundfile = TRUE; + break; + } + } + } + + if(!foundfile) + { + ERR_ErrorAt(tk_SourceName, tk_Line); + ERR_Exit(ERR_CANT_FIND_INCLUDE, YES, fileName, tk_SourceName, tk_Line); + } + + MS_Message(MSG_DEBUG, "*Include file found at %s\n", sourceName); + + // Now change the first include path to the file directory + SetLocalIncludePath(sourceName); + + tk_SourceName = AddFileName(sourceName); + size = MS_LoadFile(tk_SourceName, &FileStart); + FileEnd = FileStart+size; + FilePtr = FileStart; + tk_Line = 1; + IncLineNumber = FALSE; + tk_Token = TK_NONE; + AlreadyGot = FALSE; + BumpMasterSourceLine('x',TRUE); // dummy x + NextChr(); +} + +//========================================================================== +// +// TK_Import +// +//========================================================================== + +void TK_Import(char *fileName, enum ImportModes prevMode) +{ + TK_Include (fileName); + OpenFiles[NestDepth - 1].imported = YES; + OpenFiles[NestDepth - 1].prevMode = prevMode; + ImportMode = IMPORT_Importing; +} + +//========================================================================== +// +// PopNestedSource +// +//========================================================================== + +static int PopNestedSource(enum ImportModes *prevMode) +{ + nestInfo_t *info; + + MS_Message(MSG_DEBUG, "*Leaving %s\n", tk_SourceName); + free(FileStart); + SY_FreeConstants(NestDepth); + tk_IncludedLines += tk_Line; + info = &OpenFiles[--NestDepth]; + tk_SourceName = info->name; + FileStart = info->start; + FileEnd = info->end; + FilePtr = info->position; + tk_Line = info->line; + IncLineNumber = info->incLineNumber; + Chr = info->lastChar; + tk_Token = TK_NONE; + AlreadyGot = FALSE; + + // Pascal 12/11/08 + // Set the first include path back to this file directory + SetLocalIncludePath(tk_SourceName); + + *prevMode = info->prevMode; + return info->imported ? 2 : 0; +} + +//========================================================================== +// +// TK_CloseSource +// +//========================================================================== + +void TK_CloseSource(void) +{ + int i; + + if(SourceOpen) + { + free(FileStart); + for(i = 0; i < NestDepth; i++) + { + free(OpenFiles[i].start); + } + SourceOpen = FALSE; + } +} + +//========================================================================== +// +// TK_GetDepth +// +//========================================================================== + +int TK_GetDepth(void) +{ + return NestDepth; +} + +//========================================================================== +// +// TK_NextToken +// +//========================================================================== + +tokenType_t TK_NextToken(void) +{ + enum ImportModes prevMode; + boolean validToken; + + if(AlreadyGot == TRUE) + { + int t = MasterSourcePos; + MasterSourcePos = PrevMasterSourcePos; + PrevMasterSourcePos = t; + AlreadyGot = FALSE; + return tk_Token; + } + tk_String = TokenStringBuffer; + validToken = NO; + PrevMasterSourcePos = MasterSourcePos; + do + { + while(Chr == ASCII_SPACE) + { + NextChr(); + } + switch(ASCIIToChrCode[(byte)Chr]) + { + case CHR_EOF: + tk_Token = TK_EOF; + break; + case CHR_LETTER: + ProcessLetterToken(); + break; + case CHR_NUMBER: + ProcessNumberToken(); + break; + case CHR_QUOTE: + ProcessQuoteToken(); + break; + default: + ProcessSpecialToken(); + break; + } + if(tk_Token == TK_STARTCOMMENT) + { + SkipComment(); + } + else if(tk_Token == TK_CPPCOMMENT) + { + SkipCPPComment(); + } + else if((tk_Token == TK_EOF) && (NestDepth > 0)) + { + if (PopNestedSource(&prevMode)) + { + ImportMode = prevMode; + if(!ExporterFlagged) + { + ERR_Exit(ERR_EXPORTER_NOT_FLAGGED, YES, NULL); + } + SY_ClearShared(); + } + } + else + { + validToken = YES; + } + } while(validToken == NO); + return tk_Token; +} + +//========================================================================== +// +// TK_NextCharacter +// +//========================================================================== + +int TK_NextCharacter(void) +{ + int c; + + while(Chr == ASCII_SPACE) + { + NextChr(); + } + c = (int)Chr; + if(c == EOF_CHARACTER) + { + c = -1; + } + NextChr(); + return c; +} + +//========================================================================== +// +// TK_SkipPast +// +//========================================================================== + +void TK_SkipPast(tokenType_t token) +{ + while (tk_Token != token && tk_Token != TK_EOF) + { + TK_NextToken(); + } + TK_NextToken(); +} + +//========================================================================== +// +// TK_SkipTo +// +//========================================================================== + +void TK_SkipTo(tokenType_t token) +{ + while (tk_Token != token && tk_Token != TK_EOF) + { + TK_NextToken(); + } +} + +//========================================================================== +// +// TK_NextTokenMustBe +// +//========================================================================== + +boolean TK_NextTokenMustBe(tokenType_t token, error_t error) +{ + if(TK_NextToken() != token) + { + ERR_Error(error, YES); + /* + if(skipToken == TK_EOF) + { + ERR_Finish(); + } + else if(skipToken != TK_NONE) + { + TK_SkipPast(skipToken); + } + return NO; + */ + ERR_Finish(); + } + return YES; +} + +//========================================================================== +// +// TK_TokenMustBe +// +//========================================================================== + +boolean TK_TokenMustBe(tokenType_t token, error_t error) +{ + if (token == TK_SEMICOLON && forSemicolonHack) + { + token = TK_RPAREN; + } + if(tk_Token != token) + { + ERR_Error(error, YES); + /* + if(skipToken == TK_EOF) + { + ERR_Finish(); + } + else if(skipToken != TK_NONE) + { + while(tk_Token != skipToken) + { + TK_NextToken(); + } + } + return NO; + */ + ERR_Finish(); + } + return YES; +} + +//========================================================================== +// +// TK_Member +// +//========================================================================== + +boolean TK_Member(tokenType_t *list) +{ + int i; + + for(i = 0; list[i] != TK_NONE; i++) + { + if(tk_Token == list[i]) + { + return YES; + } + } + return NO; +} + +//========================================================================== +// +// TK_Undo +// +//========================================================================== + +void TK_Undo(void) +{ + if(tk_Token != TK_NONE) + { + if (AlreadyGot == FALSE) + { + int t = MasterSourcePos; + MasterSourcePos = PrevMasterSourcePos; + PrevMasterSourcePos = t; + AlreadyGot = TRUE; + } + } +} + +//========================================================================== +// +// ProcessLetterToken +// +//========================================================================== + +static void ProcessLetterToken(void) +{ + int i; + char *text; + + i = 0; + text = TokenStringBuffer; + while (ASCIIToChrCode[(byte)Chr] == CHR_LETTER + || ASCIIToChrCode[(byte)Chr] == CHR_NUMBER) + { + if(++i == MAX_IDENTIFIER_LENGTH) + { + ERR_Error(ERR_IDENTIFIER_TOO_LONG, YES); + } + if(i < MAX_IDENTIFIER_LENGTH) + { + *text++ = Chr; + } + NextChr(); + } + *text = 0; + MS_StrLwr(TokenStringBuffer); + if(CheckForKeyword() == FALSE + && CheckForLineSpecial() == FALSE + && CheckForConstant() == FALSE) + { + tk_Token = TK_IDENTIFIER; + } +} + +//========================================================================== +// +// CheckForKeyword +// +//========================================================================== + +static boolean CheckForKeyword(void) +{ + int min, max, probe, lexx; + + // [RH] Use a binary search + min = 0; + max = NUM_KEYWORDS-1; + probe = NUM_KEYWORDS/2; + + while (max - min >= 0) + { + lexx = strcmp(tk_String, Keywords[probe].name); + if(lexx == 0) + { + tk_Token = Keywords[probe].token; + return TRUE; + } + else if(lexx < 0) + { + max = probe-1; + } + else + { + min = probe+1; + } + probe = (max-min)/2+min; + } + return FALSE; +} + +//========================================================================== +// +// CheckForLineSpecial +// +//========================================================================== + +static boolean CheckForLineSpecial(void) +{ + symbolNode_t *sym; + + sym = SY_FindGlobal(tk_String); + if(sym == NULL) + { + return FALSE; + } + if(sym->type != SY_SPECIAL) + { + return FALSE; + } + tk_Token = TK_LINESPECIAL; + tk_SpecialValue = sym->info.special.value; + tk_SpecialArgCount = sym->info.special.argCount; + return TRUE; +} + +//========================================================================== +// +// CheckForConstant +// +//========================================================================== + +static boolean CheckForConstant(void) +{ + symbolNode_t *sym; + + sym = SY_FindGlobal(tk_String); + if(sym == NULL) + { + return FALSE; + } + if(sym->type != SY_CONSTANT) + { + return FALSE; + } + if(sym->info.constant.strValue != NULL) + { + MS_Message(MSG_DEBUG, "Constant string: %s\n", sym->info.constant.strValue); + tk_Token = TK_STRING; + tk_String = sym->info.constant.strValue; + } + else + { + tk_Token = TK_NUMBER; + tk_Number = sym->info.constant.value; + } + return TRUE; +} + +//========================================================================== +// +// ProcessNumberToken +// +//========================================================================== + +static void ProcessNumberToken(void) +{ + char c; + + c = Chr; + NextChr(); + if(c == '0' && (Chr == 'x' || Chr == 'X')) + { // Hexadecimal constant + NextChr(); + EvalHexConstant(); + return; + } + tk_Number = c-'0'; + while(ASCIIToChrCode[(byte)Chr] == CHR_NUMBER) + { + tk_Number = 10*tk_Number+(Chr-'0'); + NextChr(); + } + if(Chr == '.') + { // Fixed point + NextChr(); // Skip period + EvalFixedConstant(tk_Number); + return; + } + if(Chr == ASCII_UNDERSCORE) + { + NextChr(); // Skip underscore + EvalRadixConstant(); + return; + } + tk_Token = TK_NUMBER; +} + +//========================================================================== +// +// EvalFixedConstant +// +//========================================================================== + +static void EvalFixedConstant(int whole) +{ + double frac; + double divisor; + + frac = 0; + divisor = 1; + while(ASCIIToChrCode[(byte)Chr] == CHR_NUMBER) + { + frac = 10*frac+(Chr-'0'); + divisor *= 10; + NextChr(); + } + tk_Number = (whole<<16)+(int)(65536.0*frac/divisor); + tk_Token = TK_NUMBER; +} + +//========================================================================== +// +// EvalHexConstant +// +//========================================================================== + +static void EvalHexConstant(void) +{ + tk_Number = 0; + while(ASCIIToHexDigit[(byte)Chr] != NON_HEX_DIGIT) + { + tk_Number = (tk_Number<<4)+ASCIIToHexDigit[(byte)Chr]; + NextChr(); + } + tk_Token = TK_NUMBER; +} + +//========================================================================== +// +// EvalRadixConstant +// +//========================================================================== + +static void EvalRadixConstant(void) +{ + int radix; + int digitVal; + + radix = tk_Number; + if(radix < 2 || radix > 36) + { + ERR_Error(ERR_BAD_RADIX_CONSTANT, YES, NULL); + radix = 36; + } + tk_Number = 0; + while((digitVal = DigitValue(Chr, radix)) != -1) + { + tk_Number = radix*tk_Number+digitVal; + NextChr(); + } + tk_Token = TK_NUMBER; +} + +//========================================================================== +// +// DigitValue +// +// Returns -1 if the digit is not allowed in the specified radix. +// +//========================================================================== + +static int DigitValue(char digit, int radix) +{ + digit = toupper(digit); + if(digit < '0' || (digit > '9' && digit < 'A') || digit > 'Z') + { + return -1; + } + if(digit > '9') + { + digit = 10+digit-'A'; + } + else + { + digit -= '0'; + } + if(digit >= radix) + { + return -1; + } + return digit; +} + +//========================================================================== +// +// ProcessQuoteToken +// +//========================================================================== + +static void ProcessQuoteToken(void) +{ + int i; + char *text; + boolean escaped; + + i = 0; + escaped = FALSE; + text = TokenStringBuffer; + NextChr(); + while(Chr != EOF_CHARACTER) + { + if(Chr == ASCII_QUOTE && escaped == 0) // [JB] + { + break; + } + if(++i == MAX_QUOTED_LENGTH) + { + ERR_Error(ERR_STRING_TOO_LONG, YES, NULL); + } + if(i < MAX_QUOTED_LENGTH) + { + *text++ = Chr; + } + // escape the character after a backslash [JB] + if(Chr == '\\') + escaped ^= (Chr == '\\'); + else + escaped = FALSE; + NextChr(); + } + *text = 0; + if(Chr == ASCII_QUOTE) + { + NextChr(); + } + tk_Token = TK_STRING; +} + +//========================================================================== +// +// ProcessSpecialToken +// +//========================================================================== + +static void ProcessSpecialToken(void) +{ + char c; + + c = Chr; + NextChr(); + switch(c) + { + case '+': + switch(Chr) + { + case '=': + tk_Token = TK_ADDASSIGN; + NextChr(); + break; + case '+': + tk_Token = TK_INC; + NextChr(); + break; + default: + tk_Token = TK_PLUS; + break; + } + break; + case '-': + switch(Chr) + { + case '=': + tk_Token = TK_SUBASSIGN; + NextChr(); + break; + case '-': + tk_Token = TK_DEC; + NextChr(); + break; + default: + tk_Token = TK_MINUS; + break; + } + break; + case '*': + switch(Chr) + { + case '=': + tk_Token = TK_MULASSIGN; + NextChr(); + break; + case '/': + tk_Token = TK_ENDCOMMENT; + NextChr(); + break; + default: + tk_Token = TK_ASTERISK; + break; + } + break; + case '/': + switch(Chr) + { + case '=': + tk_Token = TK_DIVASSIGN; + NextChr(); + break; + case '/': + tk_Token = TK_CPPCOMMENT; + break; + case '*': + tk_Token = TK_STARTCOMMENT; + NextChr(); + break; + default: + tk_Token = TK_SLASH; + break; + } + break; + case '%': + if(Chr == '=') + { + tk_Token = TK_MODASSIGN; + NextChr(); + } + else + { + tk_Token = TK_PERCENT; + } + break; + case '=': + if(Chr == '=') + { + tk_Token = TK_EQ; + NextChr(); + } + else + { + tk_Token = TK_ASSIGN; + } + break; + case '<': + if(Chr == '=') + { + tk_Token = TK_LE; + NextChr(); + } + else if(Chr == '<') + { + NextChr(); + if(Chr == '=') + { + tk_Token = TK_LSASSIGN; + NextChr(); + } + else + { + tk_Token = TK_LSHIFT; + } + + } + else + { + tk_Token = TK_LT; + } + break; + case '>': + if(Chr == '=') + { + tk_Token = TK_GE; + NextChr(); + } + else if(Chr == '>') + { + NextChr(); + if(Chr == '=') + { + tk_Token = TK_RSASSIGN; + NextChr(); + } + else + { + tk_Token = TK_RSHIFT; + } + } + else + { + tk_Token = TK_GT; + } + break; + case '!': + if(Chr == '=') + { + tk_Token = TK_NE; + NextChr(); + } + else + { + tk_Token = TK_NOT; + } + break; + case '&': + if(Chr == '&') + { + tk_Token = TK_ANDLOGICAL; + NextChr(); + } + else if(Chr == '=') + { + tk_Token = TK_ANDASSIGN; + NextChr(); + } + else + { + tk_Token = TK_ANDBITWISE; + } + break; + case '|': + if(Chr == '|') + { + tk_Token = TK_ORLOGICAL; + NextChr(); + } + else if(Chr == '=') + { + tk_Token = TK_ORASSIGN; + NextChr(); + } + else + { + tk_Token = TK_ORBITWISE; + } + break; + case '(': + tk_Token = TK_LPAREN; + break; + case ')': + tk_Token = TK_RPAREN; + break; + case '{': + tk_Token = TK_LBRACE; + break; + case '}': + tk_Token = TK_RBRACE; + break; + case '[': + tk_Token = TK_LBRACKET; + break; + case ']': + tk_Token = TK_RBRACKET; + break; + case '?': + tk_Token = TK_TERNARY; + break; + case ':': + tk_Token = TK_COLON; + break; + case ';': + tk_Token = TK_SEMICOLON; + break; + case ',': + tk_Token = TK_COMMA; + break; + case '.': + tk_Token = TK_PERIOD; + break; + case '#': + tk_Token = TK_NUMBERSIGN; + break; + case '@': + tk_Token = TK_ATSIGN; + break; + case '^': + if(Chr == '=') + { + tk_Token = TK_EORASSIGN; + NextChr(); + } + else + { + tk_Token = TK_EORBITWISE; + } + break; + case '~': + tk_Token = TK_TILDE; + break; + case '\'': + if(Chr == '\\') + { + NextChr(); + switch(Chr) + { + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + tk_Number = OctalChar(); + break; + case 'x': case 'X': + NextChr(); + EvalHexConstant(); + if(Chr != '\'') + { + ERR_Exit(ERR_BAD_CHARACTER_CONSTANT, YES, NULL); + } + NextChr(); + break; + case 'a': + tk_Number = '\a'; + break; + case 'b': + tk_Number = '\b'; + break; + case 't': + tk_Number = '\t'; + break; + case 'v': + tk_Number = '\v'; + break; + case 'n': + tk_Number = '\n'; + break; + case 'f': + tk_Number = '\f'; + break; + case 'r': + tk_Number = '\r'; + break; + case '\'': + case '\\': + tk_Number = Chr; + break; + default: + ERR_Exit(ERR_BAD_CHARACTER_CONSTANT, YES, NULL); + } + tk_Token = TK_NUMBER; + } + else if(Chr == '\'') + { + ERR_Exit(ERR_BAD_CHARACTER_CONSTANT, YES, NULL); + } + else + { + tk_Number = Chr; + tk_Token = TK_NUMBER; + } + NextChr(); + if(Chr != '\'') + { + ERR_Exit(ERR_BAD_CHARACTER_CONSTANT, YES, NULL); + } + NextChr(); + break; + default: + ERR_Exit(ERR_BAD_CHARACTER, YES, NULL); + break; + } +} + +//========================================================================== +// +// NextChr +// +//========================================================================== + +static void NextChr(void) +{ + if(FilePtr >= FileEnd) + { + Chr = EOF_CHARACTER; + return; + } + if(IncLineNumber == TRUE) + { + tk_Line++; + IncLineNumber = FALSE; + BumpMasterSourceLine('x',TRUE); // dummy x + } + Chr = *FilePtr++; + if(Chr < ASCII_SPACE && Chr >= 0) // Allow high ASCII characters + { + if(Chr == '\n') + { + IncLineNumber = TRUE; + } + Chr = ASCII_SPACE; + } + BumpMasterSourceLine(Chr,FALSE); +} + +//========================================================================== +// +// PeekChr // [JB] +// +//========================================================================== + +static int PeekChr(void) +{ + char ch; + if(FilePtr >= FileEnd) + { + return EOF_CHARACTER; + } + ch = *FilePtr-1; + if(ch < ASCII_SPACE && ch >= 0) // Allow high ASCII characters + { + ch = ASCII_SPACE; + } + return ch; +} + +//========================================================================== +// +// OctalChar // [JB] +// +//========================================================================== + +static int OctalChar() +{ + int digits = 1; + int code = Chr - '0'; + while(digits < 4 && PeekChr() >= '0' && PeekChr() <= '7') + { + NextChr(); + code = (code << 3) + Chr - '0'; + } + return code; +} + +//========================================================================== +// +// SkipComment +// +//========================================================================== + +void SkipComment(void) +{ + boolean first; + + first = FALSE; + while(Chr != EOF_CHARACTER) + { + if(first == TRUE && Chr == '/') + { + break; + } + first = (Chr == '*'); + NextChr(); + } + NextChr(); +} + +//========================================================================== +// +// SkipCPPComment +// +//========================================================================== + +void SkipCPPComment(void) +{ + while(FilePtr < FileEnd) + { + if(*FilePtr++ == '\n') + { + tk_Line++; + BumpMasterSourceLine('x',TRUE); // dummy x + break; + } + } + NextChr(); +} + +//========================================================================== +// +// BumpMasterSourceLine +// +//========================================================================== + +void BumpMasterSourceLine(char Chr, boolean clear) // master line - Ty 07jan2000 +{ + if (ClearMasterSourceLine) // set to clear last time, clear now for first character + { + *MasterSourceLine = '\0'; + MasterSourcePos = 0; + ClearMasterSourceLine = FALSE; + } + if (clear) + { + ClearMasterSourceLine = TRUE; + } + else + { + if (MasterSourcePos < MAX_STATEMENT_LENGTH) + MasterSourceLine[MasterSourcePos++] = Chr; + } +} + +//========================================================================== +// +// TK_SkipLine +// +//========================================================================== + +void TK_SkipLine(void) +{ + char *sourcenow = tk_SourceName; + int linenow = tk_Line; + do TK_NextToken(); while (tk_Line == linenow && tk_SourceName == sourcenow && tk_Token != TK_EOF); +} diff --git a/token.h b/token.h index 538890c..388daa7 100644 --- a/token.h +++ b/token.h @@ -1,179 +1,179 @@ - -//************************************************************************** -//** -//** token.h -//** -//************************************************************************** - -#ifndef __TOKEN_H__ -#define __TOKEN_H__ - -// HEADER FILES ------------------------------------------------------------ - -#include "common.h" -#include "error.h" - -// MACROS ------------------------------------------------------------------ - -// TYPES ------------------------------------------------------------------- - -typedef enum -{ - TK_NONE, - TK_EOF, - TK_IDENTIFIER, // VALUE: (char *) tk_String - TK_STRING, // VALUE: (char *) tk_String - TK_NUMBER, // VALUE: (int) tk_Number - TK_LINESPECIAL, // VALUE: (int) tk_LineSpecial - TK_PLUS, // '+' - TK_MINUS, // '-' - TK_ASTERISK, // '*' - TK_SLASH, // '/' - TK_PERCENT, // '%' - TK_ASSIGN, // '=' - TK_ADDASSIGN, // '+=' - TK_SUBASSIGN, // '-=' - TK_MULASSIGN, // '*=' - TK_DIVASSIGN, // '/=' - TK_MODASSIGN, // '%=' - TK_INC, // '++' - TK_DEC, // '--' - TK_EQ, // '==' - TK_NE, // '!=' - TK_LT, // '<' - TK_GT, // '>' - TK_LE, // '<=' - TK_GE, // '>=' - TK_LSHIFT, // '<<' - TK_RSHIFT, // '>>' - TK_ANDLOGICAL, // '&&' - TK_ORLOGICAL, // '||' - TK_ANDBITWISE, // '&' - TK_ORBITWISE, // '|' - TK_EORBITWISE, // '^' - TK_TILDE, // '~' - TK_LPAREN, // '(' - TK_RPAREN, // ')' - TK_LBRACE, // '{' - TK_RBRACE, // '}' - TK_LBRACKET, // '[' - TK_RBRACKET, // ']' - TK_TERNARY, // '?' - TK_COLON, // ':' - TK_SEMICOLON, // ';' - TK_COMMA, // ',' - TK_PERIOD, // '.' - TK_NOT, // '!' - TK_NUMBERSIGN, // '#' - TK_CPPCOMMENT, // '//' - TK_STARTCOMMENT, // '/*' - TK_ENDCOMMENT, // '*/' - TK_BREAK, // 'break' - TK_CASE, // 'case' - TK_CONST, // 'const' - TK_CONTINUE, // 'continue' - TK_DEFAULT, // 'default' - TK_DEFINE, // 'define' - TK_DO, // 'do' - TK_ELSE, // 'else' - TK_FOR, // 'for' - TK_GOTO, // 'goto' - TK_IF, // 'if' - TK_INCLUDE, // 'include' - TK_INT, // 'int' - TK_OPEN, // 'open' - TK_PRINT, // 'print' - TK_PRINTBOLD, // 'printbold' - TK_LOG, // 'log' - TK_HUDMESSAGE, // 'hudmessage' - TK_HUDMESSAGEBOLD, // 'hudmessagebold' - TK_RESTART, // 'restart' - TK_SCRIPT, // 'script' - TK_SPECIAL, // 'special' - TK_STR, // 'str' - TK_SUSPEND, // 'suspend' - TK_SWITCH, // 'switch' - TK_TERMINATE, // 'terminate' - TK_UNTIL, // 'until' - TK_VOID, // 'void' - TK_WHILE, // 'while' - TK_WORLD, // 'world' - TK_GLOBAL, // 'global' - TK_RESPAWN, // 'respawn' [BC] - TK_DEATH, // 'death' [BC] - TK_ENTER, // 'enter' [BC] - TK_PICKUP, // 'pickup' [BC] - TK_BLUERETURN, // 'bluereturn' [BC] - TK_REDRETURN, // 'redreturn' [BC] - TK_WHITERETURN, // 'whitereturn' [BC] - TK_NOCOMPACT, // 'nocompact' - TK_LIGHTNING, // 'ligtning' - TK_CREATETRANSLATION,// 'createtranslation' - TK_FUNCTION, // 'function' - TK_RETURN, // 'return' - TK_WADAUTHOR, // 'wadauthor' - TK_NOWADAUTHOR, // 'nowadauthor' - TK_ACSEXECUTEWAIT, // 'acs_executewait' - TK_ACSNAMEDEXECUTEWAIT,// 'acs_namedexecutewait' - TK_ENCRYPTSTRINGS, // 'encryptstrings' - TK_IMPORT, // 'import' - TK_LIBRARY, // 'library' - TK_LIBDEFINE, // 'libdefine' - TK_BOOL, // 'bool' - TK_NET, // 'net' - TK_CLIENTSIDE, // 'clientside' - TK_DISCONNECT, // 'disconnect' - TK_EVENT, // 'event' [BB] - TK_UNLOADING, // 'unloading' - TK_STATIC, // 'static' - TK_ANDASSIGN, // '&=' - TK_ORASSIGN, // '|=' - TK_EORASSIGN, // '^=' - TK_LSASSIGN, // '<<=' - TK_RSASSIGN, // '>>=' - TK_STRPARAM_EVAL, // 'strparam' - TK_STRCPY, // 'strcpy' - TK_REGION, // 'region' [mxd] - TK_ENDREGION, // 'endregion' [mxd] - TK_KILL, // 'kill' [JM] - TK_REOPEN, // 'reopen' [Nash] - TK_ATSIGN, // '@' - TK_MORPHACTOR, // 'morphactor' [Dasperal] -} tokenType_t; - -// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- - -void TK_Init(void); -void TK_OpenSource(char *fileName); -void TK_Include(char *fileName); -void TK_Import(char *fileName, enum ImportModes prevMode); -void TK_CloseSource(void); -int TK_GetDepth(void); -tokenType_t TK_NextToken(void); -int TK_NextCharacter(void); -boolean TK_NextTokenMustBe(tokenType_t token, error_t error); -boolean TK_TokenMustBe(tokenType_t token, error_t error); -boolean TK_Member(tokenType_t *list); -void TK_Undo(void); -void TK_SkipLine(void); -void TK_SkipPast(tokenType_t token); -void TK_SkipTo(tokenType_t token); -void TK_AddIncludePath(char *sourceName); -void TK_AddProgramIncludePath(char *argv0); - -// PUBLIC DATA DECLARATIONS ------------------------------------------------ - -extern tokenType_t tk_Token; -extern int tk_Line; -extern int tk_Number; -extern char *tk_String; -extern int tk_SpecialValue; -extern int tk_SpecialArgCount; -extern char *tk_SourceName; -extern int tk_IncludedLines; -extern boolean forSemicolonHack; -extern char MasterSourceLine[]; // master line - Ty 07jan2000 -extern int MasterSourcePos; // master position - Ty 07jan2000 -extern boolean ClearMasterSourceLine; // ready for new line - Ty 07jan2000 - -#endif + +//************************************************************************** +//** +//** token.h +//** +//************************************************************************** + +#ifndef __TOKEN_H__ +#define __TOKEN_H__ + +// HEADER FILES ------------------------------------------------------------ + +#include "common.h" +#include "error.h" + +// MACROS ------------------------------------------------------------------ + +// TYPES ------------------------------------------------------------------- + +typedef enum +{ + TK_NONE, + TK_EOF, + TK_IDENTIFIER, // VALUE: (char *) tk_String + TK_STRING, // VALUE: (char *) tk_String + TK_NUMBER, // VALUE: (int) tk_Number + TK_LINESPECIAL, // VALUE: (int) tk_LineSpecial + TK_PLUS, // '+' + TK_MINUS, // '-' + TK_ASTERISK, // '*' + TK_SLASH, // '/' + TK_PERCENT, // '%' + TK_ASSIGN, // '=' + TK_ADDASSIGN, // '+=' + TK_SUBASSIGN, // '-=' + TK_MULASSIGN, // '*=' + TK_DIVASSIGN, // '/=' + TK_MODASSIGN, // '%=' + TK_INC, // '++' + TK_DEC, // '--' + TK_EQ, // '==' + TK_NE, // '!=' + TK_LT, // '<' + TK_GT, // '>' + TK_LE, // '<=' + TK_GE, // '>=' + TK_LSHIFT, // '<<' + TK_RSHIFT, // '>>' + TK_ANDLOGICAL, // '&&' + TK_ORLOGICAL, // '||' + TK_ANDBITWISE, // '&' + TK_ORBITWISE, // '|' + TK_EORBITWISE, // '^' + TK_TILDE, // '~' + TK_LPAREN, // '(' + TK_RPAREN, // ')' + TK_LBRACE, // '{' + TK_RBRACE, // '}' + TK_LBRACKET, // '[' + TK_RBRACKET, // ']' + TK_TERNARY, // '?' + TK_COLON, // ':' + TK_SEMICOLON, // ';' + TK_COMMA, // ',' + TK_PERIOD, // '.' + TK_NOT, // '!' + TK_NUMBERSIGN, // '#' + TK_CPPCOMMENT, // '//' + TK_STARTCOMMENT, // '/*' + TK_ENDCOMMENT, // '*/' + TK_BREAK, // 'break' + TK_CASE, // 'case' + TK_CONST, // 'const' + TK_CONTINUE, // 'continue' + TK_DEFAULT, // 'default' + TK_DEFINE, // 'define' + TK_DO, // 'do' + TK_ELSE, // 'else' + TK_FOR, // 'for' + TK_GOTO, // 'goto' + TK_IF, // 'if' + TK_INCLUDE, // 'include' + TK_INT, // 'int' + TK_OPEN, // 'open' + TK_PRINT, // 'print' + TK_PRINTBOLD, // 'printbold' + TK_LOG, // 'log' + TK_HUDMESSAGE, // 'hudmessage' + TK_HUDMESSAGEBOLD, // 'hudmessagebold' + TK_RESTART, // 'restart' + TK_SCRIPT, // 'script' + TK_SPECIAL, // 'special' + TK_STR, // 'str' + TK_SUSPEND, // 'suspend' + TK_SWITCH, // 'switch' + TK_TERMINATE, // 'terminate' + TK_UNTIL, // 'until' + TK_VOID, // 'void' + TK_WHILE, // 'while' + TK_WORLD, // 'world' + TK_GLOBAL, // 'global' + TK_RESPAWN, // 'respawn' [BC] + TK_DEATH, // 'death' [BC] + TK_ENTER, // 'enter' [BC] + TK_PICKUP, // 'pickup' [BC] + TK_BLUERETURN, // 'bluereturn' [BC] + TK_REDRETURN, // 'redreturn' [BC] + TK_WHITERETURN, // 'whitereturn' [BC] + TK_NOCOMPACT, // 'nocompact' + TK_LIGHTNING, // 'ligtning' + TK_CREATETRANSLATION,// 'createtranslation' + TK_FUNCTION, // 'function' + TK_RETURN, // 'return' + TK_WADAUTHOR, // 'wadauthor' + TK_NOWADAUTHOR, // 'nowadauthor' + TK_ACSEXECUTEWAIT, // 'acs_executewait' + TK_ACSNAMEDEXECUTEWAIT,// 'acs_namedexecutewait' + TK_ENCRYPTSTRINGS, // 'encryptstrings' + TK_IMPORT, // 'import' + TK_LIBRARY, // 'library' + TK_LIBDEFINE, // 'libdefine' + TK_BOOL, // 'bool' + TK_NET, // 'net' + TK_CLIENTSIDE, // 'clientside' + TK_DISCONNECT, // 'disconnect' + TK_EVENT, // 'event' [BB] + TK_UNLOADING, // 'unloading' + TK_STATIC, // 'static' + TK_ANDASSIGN, // '&=' + TK_ORASSIGN, // '|=' + TK_EORASSIGN, // '^=' + TK_LSASSIGN, // '<<=' + TK_RSASSIGN, // '>>=' + TK_STRPARAM_EVAL, // 'strparam' + TK_STRCPY, // 'strcpy' + TK_REGION, // 'region' [mxd] + TK_ENDREGION, // 'endregion' [mxd] + TK_KILL, // 'kill' [JM] + TK_REOPEN, // 'reopen' [Nash] + TK_ATSIGN, // '@' + TK_MORPHACTOR, // 'morphactor' [Dasperal] +} tokenType_t; + +// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- + +void TK_Init(void); +void TK_OpenSource(char *fileName); +void TK_Include(char *fileName); +void TK_Import(char *fileName, enum ImportModes prevMode); +void TK_CloseSource(void); +int TK_GetDepth(void); +tokenType_t TK_NextToken(void); +int TK_NextCharacter(void); +boolean TK_NextTokenMustBe(tokenType_t token, error_t error); +boolean TK_TokenMustBe(tokenType_t token, error_t error); +boolean TK_Member(tokenType_t *list); +void TK_Undo(void); +void TK_SkipLine(void); +void TK_SkipPast(tokenType_t token); +void TK_SkipTo(tokenType_t token); +void TK_AddIncludePath(char *sourceName); +void TK_AddProgramIncludePath(char *argv0); + +// PUBLIC DATA DECLARATIONS ------------------------------------------------ + +extern tokenType_t tk_Token; +extern int tk_Line; +extern int tk_Number; +extern char *tk_String; +extern int tk_SpecialValue; +extern int tk_SpecialArgCount; +extern char *tk_SourceName; +extern int tk_IncludedLines; +extern boolean forSemicolonHack; +extern char MasterSourceLine[]; // master line - Ty 07jan2000 +extern int MasterSourcePos; // master position - Ty 07jan2000 +extern boolean ClearMasterSourceLine; // ready for new line - Ty 07jan2000 + +#endif diff --git a/zcommon.acs b/zcommon.acs index 7a43ef9..5cdec5d 100644 --- a/zcommon.acs +++ b/zcommon.acs @@ -1,15 +1,15 @@ - -//************************************************************************** -//** -//** zcommon.acs -//** -//************************************************************************** - -// If you are not using the -h command line switch and do not want to use -// WadAuthor's error checker, you can uncomment the following line to shave -// a few bytes off the size of compiled scripts. -//#nowadauthor - -#include "zspecial.acs" -#include "zdefs.acs" -#include "zwvars.acs" + +//************************************************************************** +//** +//** zcommon.acs +//** +//************************************************************************** + +// If you are not using the -h command line switch and do not want to use +// WadAuthor's error checker, you can uncomment the following line to shave +// a few bytes off the size of compiled scripts. +//#nowadauthor + +#include "zspecial.acs" +#include "zdefs.acs" +#include "zwvars.acs" diff --git a/zwvars.acs b/zwvars.acs index 7011f56..b21f4e7 100644 --- a/zwvars.acs +++ b/zwvars.acs @@ -1,8 +1,8 @@ - -//************************************************************************** -//** -//** zwvars.acs -//** -//************************************************************************** - -// include your world-variable declarations here. + +//************************************************************************** +//** +//** zwvars.acs +//** +//************************************************************************** + +// include your world-variable declarations here.