home *** CD-ROM | disk | FTP | other *** search
- /*******************************************************
-
- The CalcPlus Class Library Version 1.0,
- Author: Vladimir Schipunov, Copyright (C) 1996
-
- This library is free software. Permission to use,
- copy, modify and redistribute the CalcPlus library
- for any purpose is hereby granted without fee,
- provided that the above copyright notice appear
- in all copies.
-
- *******************************************************/
-
- #ifndef __CALCEXPR_H
- #define __CALCEXPR_H
- #include "calclex.h"
-
- //
- // This header file contains description of the classes
- // of Expression hierarchy. Instructions to the interpreter
- // are all coded as the inheritants of class Expression.
- //
- // Class Expression is the base of hierarchy.
- // It provides representaion of the program to the interpreter
- // as the tree of expressions. When process comes to the node
- // of the tree, node calls its child nodes at first and then
- // calculates its own value.
- //
- // So, every node has its value, which is pointed by CType* v.
- // Method Calc calculates the value of the node taking values
- // of the child nodes as the arguments. For instance, the basic
- // implementation of addition could look like:
- //
- // void Addition::Calc()
- // {
- // *v = *child[0]->v + *child[1]->v;
- // }
- //
- // Process is running through all the tree and executes recursive
- // method Calculate. During the execution field 'flags' is being checked
- // for detecting errors, finishing calculation of current subtree, etc.
- //
- // Such a simple algorithm has at least one problem - no recursion
- // is allowed. In order to provide the recursion calls inside of
- // the interpreter we have stack which is used only when function loop
- // is matched.
- //
-
- class Expression : public LexObj
- {
- protected:
- virtual void Calc(); // should be overloaded
- // in most cases
-
- CheckType( int... ); // Checks type of child nodes
-
- void printx( ostream &s, Expression* ) const;
- precedence( const Expression& ) const;
-
- public:
- enum {
- exError = 1, // runtime error
- exLoop = 2, // set by LOOP
- exDone = 4, // set by RETURN
- exExit = 8, // set by EXIT
- exLink = 16, // undefined function
- exArgs = 32, // wrong number of arguments
- exRet = 64 // ret with or without result
- };
- typedef unsigned ExFlags;
- ExFlags flags;
-
- enum // precedence
- {
- opBool2,
- opBool1,
- opComp,
- opAr2,
- opAr1,
- opPower,
- opCast,
- opTerm
- };
-
- int n; // tree implementation
- Expression *father;
- Expression **child;
- CType *v; // value of the node
-
- virtual void print( ostream &s ) const;
- virtual op() const { return opTerm; }
- virtual range() const { return 0; }
-
- virtual Expression* Add( Expression* );
- virtual void Descendor( Expression*e ) { if( e ) e->father = this; }
- virtual Depth() const { return father ? father->Depth()+1 : 0; }
- virtual void Space( ostream& ) const;
- virtual AutoSpace() const { return 0; }
- virtual XFunction* xfunction() { return father ? father->xfunction() : 0; }
- virtual XBlock* xblock() { return father ? father->xblock() : 0; }
- virtual xref( int = -1 ) { return 0; }
-
- typedef void (Expression::*ExprF)();
- virtual void Recursion( ExprF, int dir = 0, int check = 1 );
- virtual void Link(){ flags = 0; }
- virtual void Push();
- virtual void Pop();
- loop( Expression* ) const;
- void RecStep( ExprF, int );
- void RecDebug();
-
- Expression( int n = 0 );
- Expression( int, Expression*... );
- virtual ~Expression();
- virtual void Calculate();
- virtual void Iterate();
- virtual const Expression* LocateError( int = exError ) const;
- static Debug;
- };
-
- #define DREC void Recursion( ExprF f, int dir = 0, int flags = 1 )
- #define XSTD {Expression::Recursion( f, dir, flags );}
- #define XREC(x) {if( x ) x->Recursion( f, dir, flags );}
-
- //
- // Help class needed for recursive calls
- //
-
- class PtrStack
- {
- public:
- CType** stack;
- int i;
- PtrStack() : stack( 0 ), i( 0 ){}
- ~PtrStack(){ delete[] stack; }
- void Push( CType* t );
- CType* Pop();
- };
-
- //
- // Immediate value like 1, 9.9, false or 'abc'
- //
-
- class XImmediate : public Expression
- {
- public:
- XImmediate( CType *u ) { v = u; }
- void print( ostream& ) const;
- void Calculate(){}
- void Calc(){}
- void Push(){}
- void Pop(){}
- };
-
- //
- // Line feed
- //
-
- class XEndl : public XImmediate
- {
- public:
- XEndl();
- void print( ostream& ) const;
- };
-
- //
- // Unary arithmetic operation
- //
-
- class XAr1 : public Expression
- {
- protected:
- char sign;
- void Calc();
- public:
- XAr1( char c, Expression *e ) : Expression( 1, e ), sign( c ) {}
- op() const { return opAr1; }
- void print( ostream& ) const;
- };
-
- //
- // Binary arithmetic operation
- //
-
- class XAr2 : public Expression
- {
- protected:
- char sign;
- void Calc();
- public:
- XAr2( Expression *e1, char c, Expression *e2 ) :
- Expression( 2, e1, e2 ), sign( c ) {}
- op() const { return opAr2; }
- range() const { return sign == '*' || sign == '/'; }
- void print( ostream& ) const;
- };
-
- //
- // Unary boolean operation
- //
-
- class XBool1 : public XAr1
- {
- protected:
- void Calc();
- public:
- XBool1( Expression *e ) : XAr1( '!', e ) {}
- op() const { return opBool1; }
- };
-
- //
- // Binary boolean operation
- //
-
- class XBool2 : public XAr2
- {
- protected:
- void Calc();
- public:
- XBool2( Expression *e1, char c,
- Expression *e2 ) : XAr2( e1, c, e2 ) {}
- op() const { return opBool2; }
- range() const { return sign=='&' ? 3 :
- sign=='|' ? 2 : sign=='i' ? 1 : 0; }
- };
-
- //
- // Comparison
- //
-
- class XComparison : public XAr2
- {
- private:
- void Calc();
- public:
- XComparison( Expression *e1, char c,
- Expression *e2 ) : XAr2(e1,c,e2) {}
- op() const { return opComp; }
- };
-
- //
- // Class Var is used for holding values of interpreter's variables
- //
-
- class Var : public PrintObj
- {
- public:
- char *name;
- CType *v;
- int isConst;
-
- Var( const char*, int isConst = 0 );
- ~Var();
- void print( ostream& ) const;
- };
-
- //
- // Variable of the interpreter,
- // field ref is non-zero when variable is passed
- // as the reference in the function call.
- // All the arrays are given by reference by default.
- //
-
- class XVariable : public Expression
- {
- protected:
- void Calc();
- public:
- PrintObj* obj;
- CType** ptr;
- int ref;
-
- XVariable( PrintObj* o, CType** p ) : obj( o ), ptr( p ), ref( 0 ){}
- XVariable( Var* var ) : obj( var ), ptr( &var->v ), ref( 0 ){}
- ~XVariable(){ v= 0; }
- void print( ostream& ) const;
- xref( int r ) { if( r>=0 ) ref = r; return ref; }
- void Calculate()
- {
- if( !n ){ v = *ptr; return; }
- Expression::Calculate();
- }
- void Push();
- void Pop();
- };
-
- //
- // Output of the expression(s)
- //
-
- class XEcho : public Expression
- {
- protected:
- void Calc();
- public:
- XEcho(){}
- void print( ostream& ) const;
- };
-
- //
- // IF ... THEN ... ELSE ... END;
- //
-
- class XConditional : public Expression
- {
- protected:
- void Calc();
- public:
- Expression *Then, *Else;
- XConditional( Expression* e, Expression *th, Expression *el = 0 ) :
- Expression( 1, e ), Then( th ), Else( el )
- { Descendor( Then ); Descendor( Else ); }
- ~XConditional(){ delete Then; delete Else; }
- void print( ostream& ) const;
- AutoSpace() const { return 1; }
- DREC
- {
- if( dir ){ XREC( Else ); XREC( Then ); }
- XSTD;
- if(!dir ){ XREC( Then ); XREC( Else ); }
- }
- };
-
- LEXEMA( LexVar, Var*, 0 )
- LEXEMA( LexFunc, XFunction*, 0 )
- LEXEMA( LexStruct, CArray*, 0 )
-
- //
- // BEGIN ... END;
- //
-
- class XBlock : public Expression
- {
- public:
- LexList vars;
- LexList funcs;
- LexList structs;
-
- XBlock();
- void print( ostream& ) const;
- AutoSpace() const { return 1; }
- const Expression* LocateError( int = exError ) const;
- XBlock* xblock(){ return this; }
- void Push();
- void Pop();
- };
-
- //
- // WHILE ... DO ... END;
- //
-
- class XWhile : public Expression
- {
- protected:
- void Calc();
- public:
- Expression *Cond;
- Expression *Action;
- Expression *Step;
-
- XWhile( Expression* cond, Expression *action, Expression *step = 0 );
- ~XWhile(){ delete Cond; delete Action; delete Step; }
- void print( ostream& ) const;
- AutoSpace() const { return 1; }
- void Calculate(){ flags = 0; Calc(); }
- DREC
- {
- if( dir ){ XREC( Action ); XREC( Step ); XREC( Cond ); }
- XSTD;
- if(!dir ){ XREC( Cond ); XREC( Step ); XREC( Action ); }
- }
- };
-
- class XLoop : public Expression
- {
- protected:
- void Calc();
- public:
- XLoop(){}
- void print( ostream& ) const;
- void Push(){}
- void Pop(){}
- };
-
- //
- // FUNCTION F( ... ) ... END;
- //
-
- class XFunction : public XBlock
- {
- public:
- char *name;
- int isProc;
- int busy;
-
- XFunction( int proc = 0, const char* name = 0 );
- ~XFunction(){ delete[] name; }
- virtual Defined() const { return n; }
- void SetName( const char* );
- void AddLocal( const char*, int );
- void print( ostream& ) const;
- Depth() const { return -1; }
- XFunction* xfunction() { return this; }
- void Push();
- void Pop();
- Args() const { return vars.NumObj; }
- };
-
- //
- // Call to function
- //
-
- class XCall : public Expression
- {
- protected:
- void Calc();
- public:
- XFunction *Func;
- XCall( XFunction* f ) : Func( f ){}
- void print( ostream& ) const;
- void Link();
- void TieArgs( int before = 1 );
- const Expression *LocateError( int = exError ) const;
- };
-
- //
- // Let fname be a string value of the name of the function f.
- // We provide the dynamic call to function f as &(fname).
- //
-
- class XDynamic : public XCall
- {
- protected:
- void Calc();
- public:
- Expression *Ptr;
- LexList *Table;
-
- XDynamic( Expression* e, LexList* t ) : XCall( 0 ),
- Ptr( e ), Table( t ){ Descendor(Ptr); }
- ~XDynamic(){ delete Ptr; }
- void print( ostream& ) const;
- DREC { if( dir ) XREC( Ptr ); XSTD; if( !dir ) XREC( Ptr ); }
- };
-
- //
- // RETURN
- //
-
- class XReturn : public Expression
- {
- protected:
- void Calc();
- public:
- XReturn(){}
- XReturn( Expression* e ) : Expression( 1, e ) {}
- void print( ostream& ) const;
- void Link();
- };
-
- //
- // EXIT
- //
-
- class XBreak : public Expression
- {
- protected:
- void Calc();
- public:
- XBreak(){}
- void print( ostream& ) const;
- void Push(){}
- void Pop(){}
- };
-
- //
- // This is an example of the set: { 1, 2, true, 'asd', 5 }.
- // Sets are actually arrays.
- //
-
- class XSet : public Expression
- {
- protected:
- void Calc();
- public:
- XSet(){}
- Contains( CType* ) const;
- void print( ostream& ) const;
- xref( int = -1 ) { return -1; }
- };
-
- class XUserFunction;
- typedef int (*DefFunction)( XUserFunction* );
- typedef XUserFunction* XPF;
-
- //
- // This class and definitions below provide convinient way
- // for implementing interpreter's functions in C++.
- // Basic functions are written in module calclib.cpp
- //
-
- class XUserFunction : public XFunction
- {
- protected:
- void Calc();
- public:
- DefFunction Func;
- XUserFunction( const char* name, DefFunction f,
- int order = 1, int proc = 0 );
- Defined() const { return 1; }
- CheckArgs( int t... ) const;
- CType* Arg( int i = 0 ) const;
- static LexList funcs;
- static Argc;
- static const char** Argv;
- };
-
- extern void RegFunc( const char*, DefFunction, int order = 1, int proc = 0 );
- extern void RegProc( const char*, DefFunction, int order = 1 );
- extern void UserLib();
-
- #define USER_FUNCTION( name )\
- static name( XUserFunction* xpf ){
-
- // argument i of function of given name has type t
-
- #define DEF_ARGV(i,name,t)\
- if( i>=xpf->vars.NumObj ) return 1;\
- CType* argv_tmp_##i = xpf->Arg(i);\
- if( !argv_tmp_##i || argv_tmp_##i->type()!=id##t ) return 1;\
- C##t & name = (C##t &)(*argv_tmp_##i);
-
- // argument i of unknown type
-
- #define DEF_ARGX(i,name)\
- if( i>=xpf->vars.NumObj ) return 1;\
- CType& name = *xpf->Arg(i);
-
- // function returns
-
- #define RETURNS(t)\
- if(!xpf->v || xpf->v->type()!=id##t)\
- { delete xpf->v; xpf->v = new C##t; }\
- C##t & ret = (C##t &)(*xpf->v);
-
- #define USER_FUNC( name )\
- USER_FUNCTION( name )
-
- #define USER_PROC( name )\
- USER_FUNCTION( name )\
- if( !xpf->v ) xpf->v = new CNil;
-
- #define USER_ERR( msg ) {\
- cerr << msg << endl;\
- return 1;}
-
- #define USER_END return 0; }
-
- #endif
-