Source: ../common/script.h


Annotated List
Files
Globals
Hierarchy
Index
// Copyright (C) 1999-2000 Open Source Telecom Corporation.
//  
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software 
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
// 
// As a special exception to the GNU General Public License, permission is 
// granted for additional uses of the text contained in its release 
// of Common C++.
// 
// The exception is that, if you link the Common C++ library with other
// files to produce an executable, this does not by itself cause the
// resulting executable to be covered by the GNU General Public License.
// Your use of that executable is in no way restricted on account of
// linking the Common C++ library code into it.
// 
// This exception does not however invalidate any other reasons why
// the executable file might be covered by the GNU General Public License.
// 
// This exception applies only to the code released under the 
// name Common C++.  If you copy code from other releases into a copy of
// Common C++, as the General Public License permits, the exception does
// not apply to the code that you add in this way.  To avoid misleading
// anyone as to the status of such modified files, you must delete
// this exception notice from them.
// 
// If you write modifications of your own for Common C++, it is your choice
// whether to permit this exception to apply to your modifications.
// If you do not wish that, delete this exception notice.  

#ifndef	__CCXX_SCRIPT_H__
#define	__CCXX_SCRIPT_H__

#ifndef __CCXX_MISC_H__
#include <cc++/misc.h>
#endif

class ScriptCommand;
class ScriptImage;
class ScriptInterp;
struct _line;

#define	TRAP_BITS (sizeof(unsigned long) * 8)
#define SCRIPT_STACK_SIZE 10
#define	KEYWORD_INDEX_SIZE 37
#define SYMBOL_INDEX_SIZE 187
#define SCRIPT_INDEX_SIZE KEYWORD_INDEX_SIZE

typedef bool (ScriptInterp::*scriptmethod_t)(void);
typedef char *(ScriptCommand::*scriptcheck_t)(struct _line *line);

#pragma pack(1)
typedef struct _symbol
{
	struct _symbol *next;
	char *id;
	struct
	{
		unsigned size : 16;
		bool initial : 1;
		bool system : 1;
		bool readonly : 1;
		bool commit : 1;
	} flags;
	char data[1];		
}	scriptsymbol_t;		
	
typedef struct _line
{
	struct _line *next;
	unsigned long mask;
	unsigned short loop;
	unsigned short line;
	unsigned short argc;
	scriptmethod_t method;
	char *cmd;
	char **args;
} scriptline_t;

typedef struct _script
{
	struct _script *next;
	struct _line *first;
	struct _line *trap[TRAP_BITS];
	struct _line *skip[10];
	unsigned long mask;
	char *name;
} scriptname_t;

typedef	struct
{
	const char *keyword;
	scriptmethod_t method;
	scriptcheck_t check;
}	SCRKEYWORDS;

#pragma pack()

/**
 * This class holds the bound keyword set for a given Bayonne style
 * script interpreter.  Application specific dialects are created
 * by deriving a application specific version of ScriptCommand which
 * then binds application specific keywords and associated methods
 * in an application derived ScriptInterp which are typecast to
 * (scriptmethod_t).
 *
 * @author David Sugar <dyfet@ostel.com>
 * @short Bayonne script keyword binding tables and compiler constants.
 */
class ScriptCommand : public Keydata, public Mutex
{
private:
	friend class ScriptImage;
	friend class ScriptInterp;

#pragma pack(1)
	typedef struct _keyword
	{
		struct _keyword *next;
		scriptmethod_t method;
		scriptcheck_t check;
		char keyword[1];
	} keyword_t;
#pragma pack()


	keyword_t *keywords[KEYWORD_INDEX_SIZE];
	char *traps[TRAP_BITS];
	ScriptImage *active;
	int keyword_count;
	int trap_count;

	/**
	 * Get the method handler associated with a given keyword.  This
	 * is used by ScriptImage when compiling.
	 *
	 * @param keyword to search for.
	 * @return method handler to execute for this keyword.
	 */
	scriptmethod_t getHandler(const char *keyword);

	/**
	 * Check keyword syntax.
	 *
	 * @return syntax error string or NULL.
	 * @param name of keyword to check.
	 */
	char *Check(char *command, scriptline_t *line);

protected:
	/**
	 * Get the trap id number associated with a trap name.
	 *
	 * @return trap id number, 0 (exit) if invalid.
	 * @param name of trap identifier.
	 */
	virtual unsigned getTrapId(const char *trap);

	/**
	 * Get a trap mask for a given identifer.  This is a virtual
	 * since some derived handlers may manipulate mask bits.
	 *
	 * @return signal mask.
	 * @param identifier.
	 */
	virtual unsigned long getTrapMask(unsigned id);

	/**
	 * A helper method for the compiler.  Converts a named
	 * trap into it's bit shifted mask.  By making it a virtual,
	 * derived dialects can add "aliases" to default trap names.
	 *
	 * @param name of trap identifier.
	 * @return bit shifted mask or 0 if invalid.
	 */
	virtual unsigned long getTrapModifier(const char *trapname)
		{return getTrapMask(trapname);};

	/**
	 * A helper method for the compiler used specifically for
	 * "^" trap subsection requests.  These will occasionally
	 * carry different attribute settings.
	 *
	 * @param name of trap identifier.
	 * @return bit shifted mask or 0 if invalid.
	 */
	virtual unsigned long getTrapMask(const char *trapname);

	/**
	 * Default compiler syntax to accept any syntax.
	 */
	char *chkIgnore(scriptline_t *line);

	/**
	 * Script compiler syntax check for certain variable using
	 * statements such as "clear".  Assumes list of valid variable
	 * arguments.
	 */
	char *chkHasVars(scriptline_t *line);

	/**
	 * Script compiler syntax check for assignment statements
	 * such as "set", "for", etc.
	 *
	 * @return syntax error message string or NULL.
	 * @param line statement.
	 */
	char *chkHasList(scriptline_t *line);

	/**
	 * Script compiler syntax check for commands that require
	 * no arguments to be present.
	 *
	 * @return syntax error message string or NULL.
	 * @param line statement.
	 */
	char *chkNoArgs(scriptline_t *line);

	/**
	 * Script compiler syntax check for commands that require
	 * one or more arguments to be present.
	 *
	 * @return syntax error message string or NULL.
	 * @param line statement.
	 */
	char *chkHasArgs(scriptline_t *line);

	/**
	 * Load a set of keywords into the system keyword table.  This
	 * provides a convenient method of initializing and adding to
	 * the keyword indexes.
	 *
	 * @param keyword entries to load.
	 */
	void Load(SCRKEYWORDS *keywords);

	/**
	 * Add a trap handler symbolic identity to the keyword table.
	 * These are used to handle signal mask coercion and event
	 * branch points in the compiler.
	 *
	 * @param requested trap name.
	 * @return assigned id number for the trap.
	 */
	int Trap(const char *name);

	/**
	 * Get count of active traps.
	 *
	 * @return count of active trap identifiers.
	 */
	inline int getCount(void)
		{return trap_count;};

	/**
	 * Perform compile time check of a specified symbol.
	 *
	 * @return syntax error message string.
	 * @param line pointer.
	 */
	virtual char *Check(scriptcheck_t check, scriptline_t *line)
		{return (this->*(check))(line);};

	/**
	 * Load a keydata entry for compile-time constants and
	 * bind the default ScriptInterp base class methods.  This
	 * class is never used alone, so no public constructor is
	 * provided.
	 *
	 * @param keydata entry for constants.
	 */
	ScriptCommand(const char *cfgfile);
};

/**
 * This class manages symbol tables for the scripting engine.  A symbol
 * is a variable with a reserved memory space.  Some derived systems, like
 * Bayonne IVR, may make use of a channel specific and global symbol
 * tables.
 *
 * @author David Sugar <dyfet@ostel.com>
 * @short Symbol table management for scripting engine.
 */ 
class ScriptSymbol : public SharedMemPager
{
private:

	int symsize;
	scriptsymbol_t *index[SYMBOL_INDEX_SIZE];

	unsigned getIndex(const char *symbol);

protected:
	/**
	 * Fetch a symbol entry.  Normally this is presumed to be from
	 * the native symbol table.  However, the use of a virtual allows
	 * one to derive special "system" symbols as needed for Bayonne
	 * dialects, as well as specify special attributes and properties
	 * for system symbols.  For example, in the Bayonne IVR, symbols
	 * might be used to retrieve the current DTMF digit buffer and
	 * count, but these are stored as and manipulated in a channel
	 * structure rather than in "symbol space".
	 *
	 * @return symbol entry or NULL if not found.
	 * @param symbol name to find or create.
	 * @param size of symbol space to create if not found.
	 */
	virtual scriptsymbol_t *getEntry(const char *symbol, int size = 0);

	/**
	 * A virtual method used when "committing" symbol changes.
	 * Normally this is a non-operation, but when system specific
	 * dialects are created, special symbols that must be converted
	 * from strings into other kinds of internal data types, or that
	 * might perform operations can be represented with the commit.
	 *
	 * @param symbol to commit.
	 */
	virtual void Commit(scriptsymbol_t *sym)
		{return;};

	/**
	 * Fetch default symbol size.
	 *
	 * @return default symbol size.
	 */
	inline int getSymbolSize(void)
		{return symsize;};

public:
	ScriptSymbol(int size, int pgsize = 1024);
	
	/**
	 * Fetch the address of the value of a given symbol identifier.
	 *
	 * @param symbol name.
	 * @return symbol buffer address, or NULL if not found.
	 */
	char *getSymbol(const char *symbol);

	/**
	 * Set a given symbol to a new value.
	 *
 	 * @param symbol name to find.
	 * @param value string to set.
	 * @return NULL if not found, else value.
	 */
	char *setSymbol(const char *symbol, const char *value = "");

	/**
	 * Create a new symbol entry of a specified size.
	 *
	 * @param symbol name to create.
	 * @param size of symbol, otherwise default size used.
	 * @param buffer or NULL if exists.
	 */
	char *setSymbol(const char *symbol, int size = 0);

	/**
	 * Clear a symbol definition.  This does not remove the
	 * entry if it already exists.  It mearly clears the initial
	 * flag so it still can appear undefined.
	 *
	 * @param symbol name to clear.
	 */
	void clrSymbol(const char *id);

	/**
	 * Purge user defined symbols and memory space.
	 */
	void Purge(void);
};

/**
 * A derivable class to hold compiled script images for active processes.
 * This includes the script image compiler itself.  Typically, a script is
 * compiled one file at a time from a directory, and the committed, during
 * the constructor in a derived class.
 *
 * @author David Sugar <dyfet@ostel.com>.
 * @short Script compiler image set.
 */
class ScriptImage : public MemPager
{
private:
	ifstream scrFile;	
	ScriptCommand *cmds;
	int refcount;
	scriptname_t *index[SCRIPT_INDEX_SIZE];
	char buffer[512];
	char *bp;
	bool quote;

	friend class ScriptInterp;

	char *getToken(void);

protected:
	/**
	 * Construct a new working image.  This must be derived to an
	 * application specific compiler that can scan directories and
	 * invoke the compiler as needed.
	 *
	 * @param cmdset of keyword table object used.
	 */
	ScriptImage(ScriptCommand *cmdset);
	
	/**
	 * The script compiler itself.  This linearly compiles a Bayonne
	 * script file that is specified.  Normally used along with a dir
	 * scanner in the constructor.
	 *
	 * @return lines of script compiled.
	 * @param name of script file to compile.
	 */
	int Compile(const char *scrfile);

	/**
	 * Used in the derived constructor to "commit" the current image
         * for new processes.  This is usually the last statement in the
	 * derived constructor.
	 */
	void Commit(void);

	/**
	 * Fetch named script.
	 *
	 * @param script name to find.
	 * @return script or NULL.
	 */
	scriptname_t *getScript(const char *name);
};	

/**
 * System script interpreter core engine class.  This class is further
 * derived to impliment application specific language dialects.
 *
 * @author David Sugar <dyfet@ostel.com>
 * @short Extensible Bayonne Scripting Engine.
 */
class ScriptInterp : public ScriptSymbol
{
private:
	typedef	struct
	{
		scriptname_t *script;
		scriptline_t *line;
		unsigned index, argc;
		char **argv;
	}	scriptcontext_t;

	ScriptCommand *cmd;
	ScriptImage *image;
	scriptcontext_t	script[SCRIPT_STACK_SIZE + 1];
	int stack;

	bool scrSlog(void);	
	bool scrElog(void);
	bool scrSet(void);
	bool scrSize(void);
	bool scrInit(void);
	bool scrClear(void);
	bool scrCall(void);
	bool scrIf(void);
	bool scrFor(void);
	bool scrDo(void);
	bool scrLoop(void);
	bool scrBreak(void);
	bool scrContinue(void);
	bool scrReturn(void);
	bool scrPop(void);
	bool scrSelect(void);

	friend class ScriptCommand;

protected:
	/**
	 * Derive a new instance of the system script interpreter.
	 *
	 * @param symsize for default symbol sizing.
	 * @param pgsize for memory fragmentation.
	 */
	ScriptInterp(ScriptCommand *cmd, int symsize, int pgsize = 1024);

	/**
	 * Fetch the active command interpreter subsystem.
	 *
	 * @return script interpreter.
	 */
	inline ScriptCommand *getCommand(void)
		{return cmd;};

	/**
	 * Used to process "conditional" arguments such as for IF/DO/LOOP
	 * statements.  The index is kept at the next logical argument
	 * so a goto can be performed if needed.
	 *
	 * @return true if conditional test is true.
	 */
	bool Conditional(void);

	/**
	 * Some systems can derive alternative "exit" commands
	 * which can call this routine after performing other
	 * operations.
	 */
	bool scrExit(void);

	/**
	 * This is often called to process branching requests.
	 */
	bool scrGoto(void);

	/**
	 * Attempt to attach script engine to active session and
	 * specify a starting script.
	 *
	 * @return false if failed to attach.
	 * @param name of script entry.
	 */
	bool Attach(const char *scrname);

	/**
	 * Detach the current script image.  If it is the last
	 * ref count and the exit flag is set, then delete it.
	 */
	void Detach(void);

	/**
	 * Used to return channel identifiers in some systems.
	 *
	 * @return channel id or 0 for none.
	 */
	virtual unsigned getId(void)
		{return 0;};

	/**
	 * Fetch next logical option but do not evaluate.  The index
	 * is advanced.
	 *
	 * @return option or NULL if end of list.
	 * @param optional default.
	 */
	char *getOption(const char *def = NULL);

	/**
	 * Fetch and evaluate next logical option. If a symbol ref.
	 * then the symbol is also expressed.  The index is advanced.
	 *
	 * @return option value or NULL if end of list.
	 * @param optional default value.
	 */
	char *getValue(const char *def = NULL);
	
	/**
	 * Fetch a variable (symbol) that will be used to store data.
	 * This advances the index.
	 *
	 * @return symbol found if any.
	 * @param optional size to allocate if new symbol.
	 */
	scriptsymbol_t *getVariable(int size = 0);

	/**
	 * Evaluate the content of an option retrieved with getOption.
	 *
	 * @return value of evaluation.
	 * @param option string.
	 */
	char *getContent(char *sym);

	/**
	 * May be used to override processing of indirect content
	 * requests.  This is used in the Bayonne IVR to fetch
	 * content constants based on language and country settings.
	 *
	 * @return symbol for indirect content.
	 * @param indirect fetch request.
	 */
	virtual scriptsymbol_t *getIndirect(char *sym)
		{return NULL;};

	/**
	 * Advance program to the next script statement.
	 */
	void Advance(void);

	/**
	 * Set error variable and advance to either the error handler
	 * or next script statement.
	 *
	 * @param error message.
	 */
	void Error(const char *error);

	/**
	 * Set the execution interpreter to a trap identifier.  If no
	 * trap id exists, then advance to next script statement (unless
	 * exit trap).
	 *
	 * @param id of trap to select numerically.
	 */
	void Trap(unsigned id);

	/**
	 * Select trap by symbolic name and execute if found, else advance
	 * to next script step (unless exit trap).
	 *
	 * @param name of trap to select.
	 */
	void Trap(const char *trapname);

	/**
	 * Attempt to push a value onto the stack.
	 *
	 * @return false if stack overflow.
	 */
	bool Push(void);

	/**
	 * Attempt to recall a previous stack level.
	 *
	 * @return false if stack underflow.
	 */
	bool Pull(void);

	/**
	 * Execute the next pending script statement.  If no statement
	 * is selected, then we execute the exit handler instead.  We
	 * can also force feed a trap identifier.
	 *
	 * @return true if advanced to next script statement already.
	 * @param optional trap branch point (also checks mask).
	 */
	bool Step(const char *trapname = NULL);

	/**
	 * Signals are used during "delayed" execution steps when a
	 * signal event has occured aynchronously with the execution
	 * of a script controlled state event handler.  This mechanism
	 * can be used in place of calling implicit "Step" traps.
	 *
	 * @return true if signal handler is not blocked.
	 * @param name of signal identifier.
	 */
	bool Signal(const char *trapname);

	/**
	 * Signals can be referenced by numeric id as well as by symbolic
	 * name.
	 *
	 * @return true if signal handler is not blocked.
	 * @param trap number of handler.
	 */
	bool Signal(unsigned trapid);

	/**
	 * Runtime execution of script handler.  This can be called in
	 * the current or derived class to invoke extensible methods.
	 *
	 * @return true if immediately ready for next step.
	 * @param derived method to call.
	 */
	virtual bool Execute(scriptmethod_t method)
		{return (this->*(method))();};

	/**
	 * Stop request handler.  Used for handling external trap
	 * requests during a "Signal".  This is needed in some state
	 * engines when the current state is being abandoned because
	 * of a signaled trap.
	 *
	 * @param signal mask forcing stop.
	 */
	virtual void Stop(unsigned long mask)
		{return;};

	/**
	 * Exit request handler.  This is called when no script line
	 * exists.  No default behavior is known.
	 */
	virtual void Exit(void) = 0;
};	

#endif


Generated by: dyfet@home.sys on Tue Apr 18 21:24:04 200.