/******************************************************************************
 *		           FREXX PROGRAMMING LANGUAGE    		      *
 ******************************************************************************

 Script.h
 
 Script structures and defines!

 *****************************************************************************/

/************************************************************************
 *                                                                      *
 * fpl.library - A run time library interpreting script langauge.       *
 * Copyright (C) 1992, 1993 FrexxWare                                   *
 * Author: Daniel Stenberg                                              *
 *                                                                      *
 * This program is free software; you can redistribute it and/or modify *
 * it under the terms of the GNU General Public License as published by *
 * the Free Software Foundation; either version 2, or (at your option)  *
 * any later version.                                                   *
 *                                                                      *
 * This program is distributed in the hope that it will be useful,      *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of       *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        *
 * GNU General Public License for more details.                         *
 *                                                                      *
 * You should have received a copy of the GNU General Public License    *
 * along with this program; if not, write to the Free Software          *
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.            *
 *                                                                      *
 * Daniel Stenberg                                                      *
 * Birger Jarlsgatan 93b 3tr                                            *
 * 113 56 Stockholm                                                     *
 * Sweden                                                               *
 *                                                                      *
 * FidoNet 2:201/328     email: dast@sth.frontec.se                     *
 *                                                                      *
 ************************************************************************/

#include <string.h>
#include "FPL.h"
#if defined(AMIGA) && defined(SHARED)
#include "LibAlloc.h" /* stack allocation routines */
#endif

/**********************************************************************
 *
 * Global defines:
 *
 *********************************************************************/

#ifndef  TRUE
#define  TRUE	1
#endif
#ifndef  FALSE
#define  FALSE	0
#endif

#define FPLTEXT_UNKNOWN_PROGRAM "<unknown program>"
/* When requesting the name of a program, and no program is available or no
   name has been given. This string will be returned! */

#define MAX_DIMS	     40  /* Maximum number of array dimensions */
#define IDENTIFIER_LEN       64
/* maximum number of characters in a function-, variable- or label name
   ANSI C Standard X3J11 states that there should be at least "31
   significant initial characters in an internal identifier or a macro name" */
#define ADDSTRING_DEFAULT     16  /* default length of a string expression */
#define ADDSTRING_INC         63  /* string expression length increase step */
#define MAX_ARGUMENTS         63 /* Maximum number of function arguments */

#define FPL_HASH_SIZE 67
/* Default hash table size. This should not be dividable with 2, 3, 4 or 5 */

#define FPL_MIN_HASH 10
/* The smallest acceptable hash table size */

#define BUF_SIZE (IDENTIFIER_LEN+3) /* "global" FPL buffer size */

#define FPL_STRVARARG     'C'
#define FPL_INTVARARG     'N'
#define FPL_STRVARARG_OPT (FPL_STRVARARG^32)
#define FPL_INTVARARG_OPT (FPL_INTVARARG^32)
#define FPL_VOIDARG       'V'
/* Internal return code symbol for `void' functions. In all ways they act as
   `int' functions, and they can in fact even return ints!!! */

#if defined(AMIGA) && defined(SHARED)
#define FPL_MIN_STACK 8000  /* smallest required stack */
#define FPL_MAX_STACK 20000 /* maximum stack left after a run */
#define FPL_MAX_LIMIT 40000 /* default maximum stack use possible */

#define FPLSTACK_MINIMUM 1000 /* Stack margin. When the stack space is below,
				 this, than realloc to a bigger one! */
#endif

#define BLOCK_ENTRIES 16	/* Number of free-block entries in the
				   free-block array */
#define MEMORY_QUEUE_SIZE 20    /* number of free blocks in the queue */

#define MEMORY_QUEUE	1	/* Yes, we'll use the memory queuing system! */

#define ALLOCBIT	(1<<31) /* set if MALLOC_STATIC */
#define SIZEBITS	~ALLOCBIT

#ifdef DEBUG
#define MEMORY_COOKIE	5	/* When using the DEBUG option, all Malloc()
				   will allocate a number of extra bytes at
				   the end of the block. These will be checked
				   to be intact when the block is freed or
				   CheckMem()'ed. This #define tells the size
				   of that block! */

#define PRE_COOKIE	5	/* Makes all allocations allocate this many
				   bytes extra before the block! */

#define DEBUGPARAMETERS , char *source, long line


#else
#define DEBUGPARAMETERS /* ignored! */
#define MEMORY_COOKIE 0
#endif

/**********************************************************************
 *
 * Compiler defines:
 *
 **********************************************************************/

#if FPL_VERSION>5
#define COMPILE(x)		GetSpecial(scr, (int)(x))
#define COMPILESYMBOL(x)	GetSymbol(scr, (char *)(x))
#define COMPILEINT(x)		GetInt(scr, (int)(x))
#define COMPILESTRING(x)	GetString(scr, (char *)(x))
#else
#define COMPILE(x)
#define COMPILESYMBOL(x)
#define COMPILEINT(x)
#define COMPILESTRING(x)
#endif

typedef enum {
  COMP_ERROR,	/* compiler error */
  COMP_START_OF_BLOCK,
  COMP_END_OF_BLOCK,
  COMP_END_OF_PROGRAM,
  COMP_SEMICOLON,
  COMP_START_OF_CODE,
  COMP_ARRAY,
  COMP_COMMA,
  COMP_POSTINC,
  COMP_PREINC,
  COMP_POSTDEC,
  COMP_PREDEC,
  COMP_NOT,
  COMP_1COMPL,
  COMP_PLUS,
  COMP_MINUS,
  COMP_EQUAL,

  COMP_LOGAND,
  COMP_BINAND,
  COMP_LOGOR,
  COMP_BINOR,
  COMP_BINXOR,
  COMP_COND1,
  COMP_COND2,
  COMP_MULTIPLY,
  COMP_REMAIN,
  COMP_LESSEQ,
  COMP_SHIFTL,
  COMP_LESS,
  COMP_GRETEQ,
  COMP_SHIFTR,
  COMP_GRET,
  COMP_NOTEQUAL,
  COMP_START_OF_ARRAYINFO,
  COMP_END_OF_ARRAYINFO,

  COMP_START_OF_PARAMETERS,
  COMP_END_OF_PARAMETERS,
  COMP_START_OF_EXPR,
  COMP_END_OF_EXPR,

  COMP_VARIABLEREF,

  COMP_ASSIGN,
  COMP_CMPPLUS,
  COMP_CMPMINUS,
  COMP_CMPMUL,
  COMP_CMPDIV,
  COMP_CMPAND,
  COMP_CMPOR,
  COMP_CMPREMAIN,
  COMP_CMPXOR,
  COMP_CMPSHIFTL,
  COMP_CMPSHIFTR,

  COMP_NO_PARAMETER,
  COMP_STRING_PARAMETER,
  COMP_INT_PARAMETER,

} CompileCode;

/**********************************************************************
 *
 * Different character defines:
 *
 **********************************************************************/

#define END 1
#define SPA 2
#define LET 4
#define DIG 8
#define HEX 16

extern const char type[];

#define CHAR_OPEN_BRACE    '{'
#define CHAR_CLOSE_BRACE   '}'
#define CHAR_OPEN_PAREN    '('
#define CHAR_CLOSE_PAREN   ')'
#define CHAR_OPEN_BRACKET  '['
#define CHAR_CLOSE_BRACKET ']'
#define CHAR_COMMA         ','
#define CHAR_SEMICOLON     ';'
#define CHAR_PLUS          '+'
#define CHAR_MINUS         '-'
#define CHAR_ONCE_COMPLEMENT '~'
#define CHAR_NOT_OPERATOR  '!'
#define CHAR_MULTIPLY      '*'
#define CHAR_DIVIDE        '/'
#define CHAR_AND           '&'
#define CHAR_OR            '|'
#define CHAR_XOR           '^'
#define CHAR_REMAIN        '%'
#define CHAR_QUESTION      '?'
#define CHAR_COLON         ':'
#define CHAR_ASSIGN        '='
#define CHAR_LESS_THAN     '<'
#define CHAR_GREATER_THAN  '>'
#define CHAR_SPACE         ' '
#define CHAR_DOLLAR	   '$'
#define CHAR_HASH	   '#'
#define CHAR_ZERO          '0'
#define CHAR_ONE           '1'
#define CHAR_TWO           '2'
#define CHAR_THREE         '3'
#define CHAR_FOUR          '4'
#define CHAR_FIVE          '5'
#define CHAR_SIX           '6'
#define CHAR_SEVEN         '7'
#define CHAR_EIGHT         '8'
#define CHAR_NINE          '9'
#define CHAR_UPPER_A	   'A'
#define CHAR_A             'a'
#define CHAR_B             'b'
#define CHAR_UPPER_C       'C'
#define CHAR_C             'c'
#define CHAR_D             'd'
#define CHAR_F             'f'
#define CHAR_UPPER_I       'I'
#define CHAR_I             'i'
#define CHAR_UPPER_N       'N'
#define CHAR_N             'n'
#define CHAR_O             'o'
#define CHAR_R             'r'
#define CHAR_UPPER_S       'S'
#define CHAR_S             's'
#define CHAR_T             't'
#define CHAR_V             'v'
#define CHAR_UPPER_X	   'X'
#define CHAR_X             'x'
#define CHAR_APOSTROPHE    '\''
#define CHAR_NEWLINE       '\n'
#define CHAR_VERTICAL_TAB  '\v'
#define CHAR_CARRIAGE_RETURN '\r'
#define CHAR_ALERT         '\a'
#define CHAR_QUOTATION_MARK '\"'
#define CHAR_BACKSLASH     '\\'
#define CHAR_FORMFEED      '\f'
#define CHAR_BACKSPACE     '\b'
#define CHAR_TAB           '\t'
#define CHAR_ASCII_ZERO    '\0'

#define CASE_BIT  32

/**********************************************************************
 *
 * A bunch of useful enums:
 *
 **********************************************************************/

typedef enum {		  /* all FPL operators */
  OP_NOTHING, OP_PLUS, OP_MINUS, OP_DIVISION, OP_MULTIPLY,  OP_SHIFTL,
  OP_SHIFTR, OP_REMAIN, OP_BINAND, OP_BINOR, OP_BINXOR, OP_LOGAND,
  OP_LOGOR, OP_COMPL, OP_COND1, OP_COND2, OP_EQUAL, OP_LESSEQ, OP_GRETEQ,
  OP_LESS, OP_GRET, OP_NOTEQ, OP_NOT,

  OP_PREINC, /* pre increment */
  OP_PREDEC  /* pre decrement */
#ifdef NEXT_GENERATION
    , OP_COMMA, OP_ASSIGN, OP_PLUSASSIGN, OP_MINUSASSIGN,
    OP_ORASSIGN, OP_XORASSIGN, OP_ANDASSIGN, OP_LSHIFTASSIGN, OP_RSHIFT_ASSIGN,
    OP_REMAINASIGN, OP_MULASSIGN
#endif
    } Operator;

typedef enum { /* the internal functions and keywords */
  CMD_AUTO=-200,
  CMD_BREAK,
  CMD_CONST,
  CMD_CONTINUE,
  CMD_DO,
  CMD_EXIT,
  CMD_EXPORT,
  CMD_FOR,
  CMD_IF,
  CMD_INT,
  CMD_REGISTER,
  CMD_RESIZE,
  CMD_RETURN,
  CMD_SIGNED,
  CMD_STATIC,
  CMD_STRING,
  CMD_TYPEDEF,
  CMD_UNSIGNED,
  CMD_VOID,
  CMD_VOLATILE,
  CMD_WHILE,

  FNC_ABS=-100,
  FNC_JOINSTR,
  FNC_ATOI,
  FNC_EVAL,
  FNC_ITOA,
  FNC_ITOC,
  FNC_STRCMP,
  FNC_SUBSTR,
  FNC_STRLEN,
  FNC_STRNCMP,
  FNC_STRSTR,
  FNC_STRTOL,
  FNC_LTOSTR,
  FNC_INTERPRET,

  LAST_INTERNAL /* must be the last of these ones! */
  } Funcs;

/**********************************************************************
 *
 * Debug macro defines.
 *
 *********************************************************************/

#ifdef DEBUG
/* If debugging, use the mem integer to debug the MALLOC/FREE balance! */
extern long mem;
extern long maxmem;
#endif

/**********************************************************************
 *
 * Script() control bits:
 *
 *********************************************************************/

#define SCR_NORMAL  0   /*  */
#define SCR_IF      1
#define SCR_WHILE   2
#define SCR_DO      4
#define SCR_FOR     8
#define SCR_LOOP    (SCR_WHILE|SCR_DO|SCR_FOR)
#define SCR_FUNCTION 16
#define SCR_BRACE   32  /* Declaration is allowed! This started with a brace -
			   should end with a brace, return(), break or exit()
			   */
#define SCR_RETURN_STRING 64 /* This function is declared to return a string */
#define SCR_GLOBAL 128

/***********************************************************************
 *
 * Expression() control bits:
 *
 **********************************************************************/

#define CON_NORMAL     0      /* normal statement */
#define CON_DECLINT    (1<<0) /* int declaration statement */
#define CON_DECLSTR    (1<<1) /* string declaration statement */
#define CON_GROUNDLVL  (1<<2) /* this statement starts at the ground level */
#define CON_SEMICOLON  (1<<3) /* forces Statement() to return positive on ";"
				 statement. Designed to support "for(;;)". */
#define CON_PAREN      (1<<4) /* support for the last expression of the for(;;)
				 ones */
#define CON_ACTION     (1<<5) /* This flag forces Statement() to report errror
				 if no "action" was made in the statement just
				 parsed. */
#define CON_END        (1<<6) /* Tell statement() there can be no
				 "UNEXPECTED_END".*/
#define CON_NUM        (1<<7) /* Only accept numerical statements! */
#define CON_STRING     (1<<8) /* Hint about this being a string statement! */
#define CON_DECLVOID   (1<<9) /* Declaration of a `void' function! */
#define CON_DECLEXP    (1<<10) /* Declaration of an `export' symbol */
#define CON_DECLGLOB   (1<<11) /* Declaration of a global symbol! */
#define CON_IDENT      (1<<12) /* The local parameter points to an already
				  parsed "struct Identifier" */
#define CON_DECL8      (1<<13) /* Declaration of an eight bit variable */
#define CON_DECL16     (1<<14) /* Declaration of an sixteen bit variable */
#define CON_DECLUNSIGN (1<<15) /* Unsigned declaration */
#define CON_DECLCONST  (1<<16) /* Constant declaration (read only) */
#define CON_DECLSTATIC (1<<17) /* Static declaration */

#define CON_LESSTHAN32 (CON_DECL8|CON_DECL16)
#define CON_DECLARE (CON_DECLINT|CON_DECLSTR|CON_DECLVOID) /* declaration */

/***********************************************************************
 *
 * A bunch of useful macros:
 *
 **********************************************************************/

  /* CALL - macro performing the instruction inside parentheses and receiving
     the return code in `ret'. If `ret' happens to become non-zero, a
     "return(ret);" will be performed! */
#define CALL(func) if(ret=func) return(ret)

  /* GETMEM - macro allocating memory and returning FPL_OUT_OF_MEMORY if it
     fails! */

#define GETMEM(var,size) if(!(var=(void *)MALLOC(size))) \
  return(FPL_OUT_OF_MEMORY);

  /* GETMEMA - macro allocating static memory and returning FPL_OUT_OF_MEMORY
     if it fails! */

#define GETMEMA(var,size) if(!(var=(void *)MALLOCA(size))) \
  return(FPL_OUT_OF_MEMORY);

  /* STRDUP - macro instead of the common strdup() ! */

#define STRDUP(var, pointer) \
  GETMEM(var, strlen((char *)(pointer))+1);\
  strcpy(var, (pointer));

  /* STRDUPA - macro instead of the common strdup() for STATIC allocs ! */

#define STRDUPA(var, pointer) \
  GETMEMA(var, strlen((char *)(pointer))+1);\
  strcpy(var, (char *)(pointer));



  /* WSPACE - macro returning true if the argument character is a whitespace */
#define WSPACE(x) (type[x]&SPA)

  /* WWSPACE - macro increasing the argument char pointer until it no longer
     points to a WSPACE character */
#define WWSPACE(x) while(WSPACE(*(x))) (x)++;

  /* NUMBER - returns true if the character argument is a valid decimal (0-9)
     digit */
#define NUMBER(x) (type[x]&DIG)

  /* ALPHA - returns true if the character argument is a valid character that
     an identifier can start with */
#define ALPHA(x) (type[x]&LET)

  /* ALPHANUM - returns true if the character argument is a valid character
     or number */
#define ALPHANUM(x) (type[x]&(LET|DIG))

  /* HEX - returns true if the character argument is a valid hexadecimal member
     */
#define HEXANUM(x) (type[x]&HEX)

  /* UPPER - returns uppercase version any a-z character */
#define UPPER(x) ((x)&~CASE_BIT)

  /* ABS - returns the absolute value of the argument */
#define ABS(x) ((x)>0?x:-x)

  /* MIN - returns the minimum value of the two input arguments */
#define MIN(x,y) ((x)<(y)?(x):(y))

  /* MIN3 - returns the minimum value of the three input arguments */
#define MIN3(x,y,z) MIN( MIN((x),(y)) ,(z))

#define ASSIGN_OPERATOR ( \
			 (scr->text[0]==CHAR_ASSIGN &&		\
			  scr->text[1]!=CHAR_ASSIGN) ||		\
			 ((scr->text[0]==CHAR_PLUS ||		\
			  scr->text[0]==CHAR_MINUS ||		\
			  scr->text[0]==CHAR_MULTIPLY ||	\
			  scr->text[0]==CHAR_DIVIDE ||		\
			  scr->text[0]==CHAR_AND ||		\
			  scr->text[0]==CHAR_OR ||		\
			  scr->text[0]==CHAR_REMAIN ||		\
			  scr->text[0]==CHAR_XOR) &&		\
			 scr->text[1]==CHAR_ASSIGN) ||		\
			 !strncmp("<<=", scr->text, 3) ||	\
			 !strncmp(">>=", scr->text, 3)		\
			)

/***********************************************************************
 *
 * Defines:
 *
 **********************************************************************/

#define MALLOC_DYNAMIC 0
#define MALLOC_STATIC  1

#ifdef DEBUG
#define MALLOC(x) MallocCycle(scr, x, __FILE__, __LINE__)
#define MALLOCA(x) Malloc(scr, (x), MALLOC_STATIC, __FILE__, __LINE__)
#else
#define MALLOC(x) MallocCycle(scr, x)
#define MALLOCA(x) Malloc(scr, (x), MALLOC_STATIC)
#endif

#define FREE(x) FreeCycle(scr, (void *)(x))
#define FREEA(x) Free(scr, (void *)(x), MALLOC_STATIC)

#define FREEALL() FreeAll(scr, MALLOC_DYNAMIC)
#define FREEALLA() FreeAll(scr, MALLOC_STATIC)

/* old version:
   #define GETSTRLEN(str) ((long)*(long *)(str))
   */
#define GETSTRLEN(str) (((struct fplStr *)(((char *)str)-offsetof(struct fplStr, string)))->len)

#if defined(AMIGA)
  /*
   * We have to make all external referenced functions to receive the
   * parameters in certain registers and restore the A4 register.
   */

#define PREFIX __asm __saveds   /* special SAS/C ideas! Forces arguments
				   to be puched in specified registers and
				   forces the A4 register to be loaded at the
				   beginning of the funtion. */
#define REG(x) register __ ## x
#define ASM __asm
#else
  /*
   * No need for any of those!
   */
#define PREFIX
#define REG(x)
#define ASM
#endif

#if defined(AMIGA) /* the amiga library defines... */
#define INLINE __inline
#else
#define INLINE
#endif

/**********************************************************************
 *
 * Create some structures and define their flags:
 *
 *********************************************************************/

struct Unary {
  Operator unary;
  struct Unary *next;
};

struct InsideFunction {
  /*
   * Used for `inside' functions.
   */

  char ret;
  char *format; 
  
  long col; /* column number of the inside function position. */
  long prg; /* line number of the function */
  char *file; /* name of file where this function resides */
  long virprg; /* virtual line number */
  char *virfile; /* virtual file name */
};

struct ExternalFunction {
  /*
   * Used for all other functions and keywords.
   */
  char ret; /* 'I' - returns an integer
	       'S' - returns a string
	       */
  char *format; /* Parameter format. Zero terminated. Unlimited length.
		   'I' - integer
		   'S' - string
		   'C' - string variable structure
		   'N' - integer variable structure
		   '>' - variable number of the previous type.

		   NULL pointer - no argument at all.
		   lower case - optional (must only be to the right of
		   the required)
		     
		   Ex: "ISsc"
		   means that the function requires two parameters:
		   one integer and one string. It has two optional
		   parameters: one string and one string variable. */
  long ID; /* Identifier ID. This information is sent in the
	      fplArgument structure.
	      <0 is reserved for FPL internals. */

  void *data; /* function specific data! */
  long (*func)(void *); /* optional function! */
};

struct fplStr {
  /*
   * FPL 'string' structure!
   */
  long alloc;     /* Allocated length of following string. That goes for the
		     string *only*! The structure's size have to be added if
		     the entire alloc is wanted! Notice that the first (or
		     last) byte in the string belongs to the structure and
		     not the 'string'!!! */
  long len;	  /* length of following string */
  char string[1]; /* memory included in the string! */
};

struct fplVariable {
  struct fplVariable *temp; /* Used when passing variable references. */

  long *dims;  /* An array holding the size of each dimension. */
  long num;    /* Number of dimensions */
  long size;   /* Number of variables in this array, that it is all
		  dims' members multiplied with each other! */
  /*
   * Variable values to read. This is an array of values if the variable
   * was declared as an array!
   */
  union {
    struct fplStr **str; /* FPL string  */
    long *val32;	/* FPL integer */
    short *val16;	/* FPL short   */
    char *val8;		/* FPL char    */
    void *val;		/* general FPL data pointer */
  } var;
};

struct Identifier {
  /* This structure is used to store all identifiers in when they are "hashed
     in". Notice that *ALL* data in this structure is pointing and referring
     to the very same data as was sent to it, which means that you must keep
     that data intact while using FPL. */

  char *name; /* Indentifier. Must be absolutely unique and not more than
		 MAX_COMMAND_LEN characters long. */

  union {
    struct ExternalFunction external;
    struct InsideFunction inside;
    struct fplVariable variable;
  } data;
  
  unsigned long flags; /* See below! */

  char *file;	/* file name of the file in which we find this identifier
		   0 if exported global */
  
  struct Identifier *func; /* It exists only under this function. Pointer might
			      be NULL if in no-name function! */

  long level; /* In which level this exists.
		 Variables exist in all levels below (with a higher number)
		 where it was declared. Two declarations using the same
		 name in the same level is not allowed!
		 LONG_MAX if global! */
  
  unsigned long hash; /* Hash value. To get the proper hash table entry for
			 this, use [hash%HASH_TABLE_SIZE] */
  
  /* Bidirectional links to keep a hash value sorted order among
     functions using the same hash table entry: */
  struct Identifier *prev;
  struct Identifier *next;
};

/****** Identifier.flags defines:  ******/

/* Data type */

#define FPL_STRING_VARIABLE   (1<<0)  /* string variable */
#define FPL_INT_VARIABLE      (1<<1)  /* integer variable */
#define FPL_COPIED_DATA       (1<<2)  /* identifier reference */
#define FPL_INTERNAL_FUNCTION (1<<3)  /* internal FPL function */
#define FPL_EXTERNAL_FUNCTION (1<<4)  /* user supplied external function */
#define FPL_INSIDE_FUNCTION   (1<<5)  /* inside function in any program */
#define FPL_KEYWORD	      (1<<10) /* this is a keyword identifier! */
#define FPL_KEYWORD_DECLARE   (1<<11) /* declaring keyword */
#define FPL_INSIDE_NOTFOUND   (1<<15) /* This inside function has not been
					 discovered yet. The position the
					 data points to is the search start
					 position. */
#define FPL_IGNORE            (1<<17) /* Read this and then drop it! */
/* Data status */

#define FPL_READONLY          (1<<6)  /* const variable! */
#define FPL_HIJACKED_VARIABLE (1<<7)  /* hijacked variable! */
#define FPL_EXPORT_SYMBOL     (1<<8)  /* cross program accessible */
#define FPL_GLOBAL_SYMBOL     (1<<9)  /* global accessible in one file */
#define FPL_SHORT_VARIABLE    (1<<12) /* short (16-bit) variable */
#define FPL_CHAR_VARIABLE     (1<<13) /* char (8-bit) variable */
#define FPL_UNSIGNED_VARIABLE (1<<14) /* unsigned variable */
#define FPL_STATIC_VARIABLE   (1<<16) /* static variable! */


#define FPL_NONGLOBAL	      (1<<17) /* delete global status! */

#define FPL_STATUS (FPL_READONLY|FPL_HIJACKED_VARIABLE|FPL_EXPORT_SYMBOL\
		    FPL_GLOBAL_SYMBOL|FPL_SHORT_VARIABLE|FPL_CHAR_VARIABLE\
		    FPL_UNSIGNED_VARIABLE|FPL_STATIC_VARIABLE|FPL_NONGLOBAL)

/*
 * These two lower flags should be combined with the "Data status" flags
 * when declaring variables!
 */

#define FPLDECL_STRING	      (1<<31) /* Keyword declaring string */
#define FPLDEC_INT	      (1<<30) /* Keyword declaring int */


#define FPL_VARIABLE_LESS32 (FPL_SHORT_VARIABLE|FPL_CHAR_VARIABLE)
#define FPL_VARIABLE (FPL_STRING_VARIABLE|FPL_INT_VARIABLE)
#define FPL_FUNCTION (FPL_INTERNAL_FUNCTION|FPL_EXTERNAL_FUNCTION |\
		      FPL_INSIDE_FUNCTION)

/***** Identifier.ID defines: ******/

#define FPL_INSIDE_FUNCTION_ID -3;

struct Condition {
  char *bracetext;  /* pointer to the character to the right of the open
		       brace */
  long braceprg;    /* line number of the above data */
  char *check;      /* pointer to the expression. Used by while() and for() */
  long checkl;      /* the line number of the expression */
  char *postexpr;   /* USED BY "for" : pointer to statement3 */
  long postexprl;   /* USED BY "for" : statement3's line number */
};

struct Expr {  /* the numerical expression linked list */
  union {
    long val;		/* numerical return */
    struct fplStr *str; /* string return */
  } val;
  Operator operator;  /* see the operator enums! */
  struct Unary *unary; /* unary/primary operators linked list! */
  char flags;	      /* see below */
  struct Expr *next; 
};

/**** struct Expr.flags defines: ****/
#define FPL_STRING     (1<<0) /* Expr structure is a string. */
#define FPL_NOFREE     (1<<1) /* A returned string should not be freed */
#define FPL_OPERAND    (1<<2) /* Next part in the expression is a operand */
#define FPL_ACTION     (1<<3) /* The expression includes any variable change(s) */
#define FPL_BREAK      (1<<4) /* The val member specifies number of levels
				 left to break from! */
#define FPL_RETURN     (1<<5) /* There is a return call received, return to the
				 last function caller. */
#define FPL_CONTINUE   (1<<6) /* Continue is flagged! */

#define FPL_DEFUNCTION (1<<7) /* The Expression() just called declared AND
				 defined a function! */


struct Local {
  /*
   * This structure will create a linked list of all local variables declared
   * in this level. When leaving this level, *ALL* variables with the names
   * that the ->ident member points to must be deleted, using DelIdentifier().
   */
  struct Identifier *ident;
		/* This pointer points to the Identifier structure,
		   that means this should *NOT* be freed individually
		   but only the entire structure and the Identifier structure
		   (and members) at the same time! */
  struct Local *next; /* Next member in this chain */
};

/*
 * All fplFunction ID's below zero are reserved for FPL internal use.
 * We use the funcdata member to set some flags:
 */
#define FPL_HASH_INSIDE   1
#define FPL_HASH_INTERNAL 2

struct Program {
  struct Program *next;
  char *name;		/* unique name of program */
  long running;		/* true if running */
  long openings;	/* number of invokes! */
  char *program;	/* program pointer or NULL if not present in memory */
  long lines;		/* number of lines */
  long size;		/* total size in number of bytes */
  long flags;		/* see defines below */

  long startcol;	/* Where "main" started. Column number */
  long startprg;	/* Where "main" started. Line number */
  long virprg;		/* Virtual line number of "main" */
  char *virfile;	/* virtual file name of "main" */
  long column;		/* Last interpreted column!
			   _ONLY_ to read if this program isn't opened! */
#ifdef AMIGA
  void *lock;		/* if using the FPLTAG_LOCKUSED, this is the lock of
			   this particular file! */
#endif
  long warnings;	/* number of warnings found in this file! */
};

/* Program.flags: */
#define PR_USERSUPPLIED 1
/* This program is user supplied. That means that FPL has *not* allocated the
   memory this program uses, making no straight flushes allowed! */

#define PR_CACHEFILE 2
/* This program should be cached until anything else is said! */

#define PR_FILENAMEFLUSH 4
/* When this program is flushed, it can always be restored by using the
   program name as file name to read from! */

#define PR_TEMPORARY 8
/* This isn't a real program but only created for a temporary usage reason! */

#define PR_GLOBALSTORED 16
/* This program has got it's global symbols stored! */

#define PR_CACHEEXPORTS 32
/* This program should be cached only if exports are declared */

struct Store {
  /*
   * This is all data that should be backuped when recursing, and
   * restored when the recursing function ends.
   */
  char *text;
  long prg;
  char strret;
  long level;
  long varlevel;
  char *virfile;
  long virprg;
  char *interpret;
  struct Local *globals;
  struct fplMsg *msg;
  struct Program *prog;
  struct Local *locals;
};

struct Data {
  /*
   * Allocated at fplInit() and freed at fplFree().
   */
#ifdef AMIGA
  char *stack_base;	/* our new stack base */
  long stack_size;	/* requested stack size! */
  long stack_max;	/* Maximum stack left after a FPL function call */
  long stack_limit;	/* absolute maximum stack usage allowed */
  long stack_margin;	/* minimum stack required to call the interface
			   function! */
  long registers[11];	/* Storage for the eleven registers that should be
			   brought back when calling the interface function */
#endif
  /* --------------------------------------------------------------------- */
  /* If anything is changed among the above, check validity of liballoc.i! */
  /* --------------------------------------------------------------------- */

  void * ASM (*Alloc)(REG(d0) long);  /* allocate routine to use */
  void ASM (*Dealloc)(REG(a1) void *, REG(d0) long); /* dealloc routine */

  long ASM (*function) (REG(a0) void *); /* Pointer to function handler. */
  long ASM (*interfunc) (REG(a0) void *); /* Function to be called every now
					     and then when executing, enabling
					     your programming to keep track of
					     different things even if FPL is in
					     charge! */
  long ASM (*newline_hook)(REG(a0) void *); /* Newline hook function pointer */ 

  /********* START OF STORE STRUCT ***********/
  
  char *text;       /* Current interpret position */
  long prg;         /* Current line number */

  char strret;	    /* The Script() now executing should return a
		       string! (TRUE/FALSE) */
  long level;	    /* Nesting level */
  long varlevel;    /* current variable level */

  char *virfile;    /* virtual file name occurred! */
  long virprg;	    /* virtual line number */

  char *interpret;  /* if we whould interpret anything else but the main
		       function! Set this with the FPLTAG_INTERPRET tag. */

  struct Local *globals; /* Pointer to list holding all global symbols
			    currently declared in this program. They might be
			    removed when this program quits if the user has
			    set that flag or if we miss certain information */

  struct fplMsg *msg; /* Pointer to any pending message to FPL sent from the
			 user. We expect return codes from user functions to
			 be sent using this. */

  struct Program *prog; /* Pointer to the "struct Program" holding information
			   about the program we're currently interpreting */

  struct Local *locals; /* Linked list of local variables! If any error
			   code is returned, there might be local variables
			   left to free in any precious local level! Use this
			   list to delete 'em all!
			   
			   We add *ALL* levels to one list, separated with a
			   NULL name. Deleting only the latest level, deletes
			   to the nearest NULL name!
			   */

  /********* END OF STORE STRUCT *************/

  struct Program *programs; /* list with all files information */
  long ret;		/* Return value of the FPL block */
  char *buf;		/* Global buffer pointer (Why use more than one buffer
			   at a time? It's only a waste of valuable stack!) */
  void *userdata;       /* Global Userdata. Free to use. */
  unsigned char flags;  /* Flags. See defines below! */
  long data;	        /* The result of the interfunc. */
  long FPLret;	        /* FPL return code = the result of the
			   "exit(RETURN_CODE);" call! */
  long hash_size;	/* hash table size! */
  struct Identifier **hash;  /* Must be set to NULL before doing anything
				major... like using fplAddFunction() or
				calling fplExecute[File]() The NULL-setting is
				done by fplInit(). */

  struct Local *usersym; /* Pointer to list holding all global symbols
			    declared in another FPL program run. These symbols
			    are legal global symbols */
  
  struct MemInfo *MallocKey[2]; /* We have two mallockey pointers because we
				   have two different kinds of Malloc()s! One
				   for each execution and one for each
				   fplInit(). */
  struct FreeBlock *blox[BLOCK_ENTRIES]; /* memory caching tables */
  long blockcount[BLOCK_ENTRIES]; /* memory caching table counters */
  struct Identifier *func; /* pointer to the current interpreted function
			      or NULL */
  long runs;

  char compiling; /* TRUE if compiling!!! */
};

/***** Data.flags: *****/

#define FPLDATA_ALLFUNCTIONS (1<<0)
/* Accept all functions, even if not found! */

#define FPLDATA_CACHEFILE (1<<1)
/* This file should be cached among the other global data. */

#define FPLDATA_CACHEALLFILES (1<<2)
/* This makes FPL store all files in memory that it has to remember */

#define FPLDATA_CACHEEXPORTS (1<<3)
/* This makes FPL store all files in memory that exports symbols */

#define FPLDATA_LOCKUSED (1<<5)
/* Lock() the current files! */

struct fplMsg {
  struct fplMsg *next;  /* next message struct */
  struct fplMsg *prev;	/* when priority is allowed, things might be inserted
			   virtually anywhere in the list */
  char type;		/* type of message. See defined below! */
  void *message[4];	/* different meanings depending on the type */
};

#define FPLMSG_RETURN_INT     1 /* message[0] is a long integer */
#define FPLMSG_RETURN_STRING  2 /* message[0] is the FPL-type string */
#define FPLMSG_STOP	      3 /* message[0] is to be stored in Data->data
				   as the "result of the last interfunc". */
#define FPLMSG_PROGRAM	      4 /* message[0] is a (char **) to the program
				   array, message[1] is zero or the new number
				   of lines and message[2] is zero or the new
				   program size. */
#define FPLMSG_CONFIRM	      5 /* message[0] is TRUE/FALSE */
#define FPLMSG_GLOBAL	      6 /* Global symbol reading is ordered.
				   (FPLSEND_GLOBALSYMBOLS)
				   message[0] holds the current pointer to a
				   struct Local */


/**********************************************************************
 *                                                                    *
 * All functions used from external functions.                        *
 *                                                                    *
 **********************************************************************/

ReturnCode PREFIX fplExecuteScript(REG(a0) struct Data *,
				   REG(a1) char **,
				   REG(d1) long,
				   REG(a2) unsigned long *);
ReturnCode PREFIX fplExecuteFile(REG(a0) struct Data *,
				 REG(a1) char *,
				 REG(a2) unsigned long *);
char * PREFIX fplGetErrorMsg(REG(a0) struct Data *,
			     REG(d0) long,
			     REG(a1) char *);
void * ASM fplInit(REG(a0) long (*)(void *),
		   REG(a1) unsigned long *);
void PREFIX fplFree(REG(a0) void *);
ReturnCode PREFIX fplAddFunction(REG(a0) struct Data *,
				 REG(a1) char *,
				 REG(d0) long,
				 REG(d1) char,
				 REG(a2) char *,
				 REG(a3) unsigned long *);
ReturnCode PREFIX fplDelFunction(REG(a0) struct Data *,
				 REG(a1) char *);
ReturnCode PREFIX fplReset(REG(a0) struct Data *,
			   REG(a1) unsigned long *);
ReturnCode PREFIX fplSend(REG(a0) struct Data *,
			  REG(a1) unsigned long *);
void PREFIX *fplAlloc(REG(a0) struct Data *,
		      REG(d0) long);
void PREFIX fplDealloc(REG(a0) struct Data *,
		       REG(a1) void *);
void PREFIX *fplAlloca(REG(a0) struct Data *,
		       REG(d0) long);
void PREFIX fplDealloca(REG(a0) struct Data *,
		        REG(a1) void *);
long PREFIX fplConvertString(REG(a0) struct Data *,
			     REG(a1) char *,
			     REG(a2) char *);
ReturnCode PREFIX fplCallFunction(REG(a0) struct Data *,
				  REG(a1) char *,
				  REG(d0) long,
				  REG(a2) void **,
				  REG(a3) char *format,
				  REG(a4) unsigned long *);

#ifdef HIJACK
ReturnCode PREFIX fplHijack(REG(a0) struct Data *,
			    REG(a1) char *);
#endif

/**********************************************************************
 * All functions used globally in the library.                        *
 **********************************************************************/
ReturnCode Script(struct Data *, struct Expr *, char, struct Condition *);
ReturnCode Expression(struct Expr *, struct Data *, long, struct Identifier *);
ReturnCode Eat(struct Data *);
ReturnCode Getword(char *, struct Data *);

#ifdef UNIX
long InterfaceCall(struct Data *, void *, long (*)(void *));
/* The Amiga version has this function coded in assembler */
#endif

ReturnCode DelProgram(struct Data *, struct Program *);
ReturnCode ReadFile(void *, char *, struct Program *);
ReturnCode Newline(struct Data *);
long Strtol(char *, long, char **);

ReturnCode NewMember(struct Data *, struct Expr **);
ReturnCode AddVar(struct Data *, struct Identifier *, struct Local **);
ReturnCode ReturnChar(struct Data *, long *, char);
ReturnCode GetEnd(struct Data *, char, char, char);
ReturnCode CmpAssign(struct Data *, long, long *, long, char);
ReturnCode StrAssign(struct fplStr *, struct Data *, struct fplStr **, char);

ReturnCode GetProgram(struct Data *, struct Program *);
ReturnCode LeaveProgram(struct Data *, struct Program *);
ReturnCode Warn(struct Data *, ReturnCode);

ReturnCode DeleteMessage(struct Data *, struct fplMsg *);
ReturnCode GetMessage(struct Data *, char, struct fplMsg **);
ReturnCode functions(struct fplArgument *);

ReturnCode GetIdentifier(struct Data *, char *, struct Identifier **);
ReturnCode DelIdentifier(struct Data *, char *, struct Identifier *);
void ASM *DefaultAlloc(REG(d0) long);
void ASM DefaultDealloc(REG(a1) void *, REG(d0) long);
ReturnCode DelLocalVar(struct Data *, struct Local **);
ReturnCode AddLevel(struct Data *);

void SwapMem(struct Data *, void *, char);
void ASM Free(REG(a0) struct Data *, REG(a1) void *, REG(d0) char);
void FreeCycle(struct Data *, void *);
void FreeAll(struct Data *, char);
void ASM *Malloc(REG(a0) struct Data *, REG(d0) long ,
		 REG(d1) char DEBUGPARAMETERS);
void *MallocCycle(struct Data *, long DEBUGPARAMETERS);
void InitFree(struct Data *);
void FlushFree(struct Data *);
void CleanUp(struct Data *, long, long);
#ifdef DEBUG
ReturnCode CheckMem(struct Data *, void *);
#endif

/*************
  Compile prototypes!
**************/

ReturnCode GetString(struct Data *, char *);
ReturnCode GetSymbol(struct Data *, char *);
ReturnCode GetInt(struct Data *, int);
ReturnCode GetSpecial(struct Data *, CompileCode);

