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.
-
- *******************************************************/
-
- %{
- //#define YYDEBUG
- #include <iostream.h>
- #include <stdarg.h>
- #include <stdio.h>
- #include "yycalc.h"
- #include "calcexpr.h"
- #include "calctype.h"
- class Expression;
- #define yyparse CalcPlus::yyparse
-
- #define XSEQ ((XBlock*)(Blocks.Last()))
- #define XBEG {XBlock *x = new XBlock; Blocks.Push(x);}
- #define XEND {Blocks.Pop();}
- #define COND(x) ((XBlock*)(Cond##x.Last()))
- #define YYMAXDEPTH 100
- %}
-
- %union {
- char c;
- long i;
- double r;
- char* s;
- Var* v;
- CArray* a;
- XFunction* f;
- Expression* e;
- XVariable* x;
- }
-
- /*
- Note that lexical analizer returns "lx***" for simple
- lexical tokens and "yy***" if symbol is already declared.
- */
-
- %token lxInt lxReal lxName lxVar lxStep lxAssign
- %token lxFunc lxGe lxLe lxNe lxEcho lxStruct
- %token lxNot lxOr lxAnd lxImp lxIf lxThen
- %token lxElse lxEndl lxTrue lxFalse lxNil lxBegin
- %token lxEnd lxWhile lxDo lxFor lxTo lxInclude
- %token lxRet lxExit lxConst lxUser lxLoop lxString
- %token lxProc lxInc lxDec lxIfdef lxEndif lxDefine
- %token lxUndef lxIfndef
- %token yyVar yyFunc yyProc yyConst yyStruct
-
- %right lxAssign
- %left lxImp
- %left lxOr
- %left lxAnd
- %right lxNot '!'
- %nonassoc '<' lxLe '>' lxGe lxNe '='
- %left '+' '-'
- %left '*' '/'
- %left '^'
-
- %type <i> lxInt step
- %type <r> lxReal
- %type <s> lxString lxName varname
- %type <v> yyVar yyConst varcnst vardecl
- %type <f> yyFunc yyProc declf extern fname func
- %type <e> term stat assign expr boolean booltmp
- %type <e> callf callp block ret lxUser array idx
- %type <a> yyStruct
- %type <x> var const
-
- /*
- Here is the short description of the language.
- I hope most of the syntax is clear because
- language looks like other procedure languages.
- Basicly syntax is:
-
- Block:
- begin
- ...
- end;
-
- Variables:
-
- var x,y;
-
- var a:=2*3;
-
- const c:=1;
-
- struct abc {a,b,c};
- abc abc_var;
-
- Funcs, procs:
-
- function f(x,y)
- ...
- end;
-
- Conditions:
-
- if expr then
- ...
- else
- ...
- end;
-
- expr1 -> expr2;
-
- Loops:
-
- while expr do
- ...
- [loop] // like continue in C
- ...
- [exit] // like break in C
- ...
- end;
-
- for i:=expr1 to expr2 [step expr3] do
- ...
- end;
-
- Output:
-
- echo exprlist;
- */
-
- %start module
- %%
- module :
- | module decl varlist';'{}
- | module struct';' {}
- | module extern';' {}
- | module func {}
- | module lxName { yyerror( "unknown symbol ", $2 ); yyerrok; }
- | module error';'{ yyerror(); yyerrok; }
- ;
- block : lxBegin { XBEG; } stats lxEnd { $$ = XSEQ; XEND; }
- ;
- decl : lxVar { DeclType = declVar; StructTmp = 0; } declstr {}
- | lxConst { DeclType = declConst; StructTmp = 0; } declstr {}
- | yyStruct { DeclType = declVar; StructTmp = $1;}
- ;
- declstr : {}
- | yyStruct { StructTmp = $1; }
- ;
- stats :
- | stats decl varlist';'{}
- | stats struct';' {}
- | stats ';' {}
- | stats stat ';' { XSEQ->Add( $2 ); }
- | stats error';' { yyerror(); yyerrok; }
- | stats lxName { yyerror( "unknown symbol ", $2 ); yyerrok; }
- ;
- stat : block { $$ = $1; }
- | callp { $$ = $1; }
- | callf { $$ = $1; }
- | assign { $$ = $1; }
- | ret { $$ = $1; }
- | lxExit { $$ = new XBreak; }
- | lxLoop { $$ = new XLoop; }
- | lxEcho { EchoTmp = new XEcho;}
- echoes { $$ = EchoTmp; }
- | boolean lxImp stat { $$ = new XConditional( $1, $3 ); }
- | lxIf booltmp lxThen stats lxEnd
- {
- $$ = new XConditional( $2, XSEQ );
- XEND;
- Cond1.Pop();
- }
- | lxIf booltmp lxThen stats
- lxElse
- {
- XEND;
- XBEG;
- Cond2.Push( XSEQ );
- } stats lxEnd
- {
- XEND;
- $$ = new XConditional( $2, COND(1), COND(2));
- Cond1.Pop();
- Cond2.Pop();
- }
- | lxWhile boolean lxDo { XBEG; } stats lxEnd
- {
- $$ = new XWhile( $2, XSEQ );
- XEND;
- }
- | lxFor yyVar lxAssign expr lxTo expr step lxDo { XBEG; } stats lxEnd
- {
- XBlock *x = XSEQ;
- XEND;
- XSEQ->Add(( new XVariable( $2 ))->Add( $4 ));
- $$ = new XWhile( new XComparison( new XVariable( $2 ),'{', $6 ),
- x, (new XVariable( $2 ))->Add( new XAr2( new XVariable( $2 ),
- '+',new XImmediate( new CLong( $7 )))));
- }
- | lxFor '(' stat ';' expr ';' stat ')' { XBEG; } stats lxEnd
- {
- XBlock *x = XSEQ;
- XEND;
- XSEQ->Add( $3 );
- $$ = new XWhile( $5, x, $7 );
- }
- | yyVar lxInc { $$ = (new XVariable( $1 ))->Add(
- new XAr2( new XVariable( $1 ), '+',
- new XImmediate( new CLong( 1 )))); }
- ;
- booltmp : boolean { XBEG; Cond1.Push( XSEQ ); $$ = $1; }
- ;
- ret : lxRet { $$ = new XReturn; }
- | lxRet expr { $$ = new XReturn( $2 ); }
- ;
- step : { $$ = 1; }
- | lxStep lxInt { $$ = $2; }
- ;
- echoes : expr { EchoTmp->Add( $1 ); }
- | echoes','expr { EchoTmp->Add( $3 ); }
- ;
- varlist : vardecl {}
- | varlist','vardecl {}
- ;
- vardecl : varname { AddVar( $1 ); }
- | varname { VarTmp = AddVar( $1 ); }
- lxAssign expr { XSEQ->Add(( new XVariable( VarTmp ))->Add( $4 ));}
- ;
- varname : lxName { $$ = $1; }
- | varcnst { $$ = $1->name;if(XSEQ->vars($1->name)){yyerrok;
- yyerror("variable ", $1->name," already exist"); }}
- ;
- varcnst : yyVar { $$ = $1; }
- | yyConst { $$ = $1; }
- ;
- assign : var lxAssign expr {( $$ = $1 )->Add( $3 ); }
- | lxUser lxAssign expr{ $$ = UserSym( $1, $3 ); }
- ;
- struct : lxStruct lxName
- {
- HideVars = 1;
- StructTmp = new CArray;
- XSEQ->structs.Add( new LexStruct( $2,
- StructTmp, yyStruct ));
- }
- '{' strings '}' { HideVars = 0; }
- ;
- strings : lxName { StructTmp->add( new CString( $1 )); }
- | strings','lxName { StructTmp->add( new CString( $3 )); }
- ;
- expr : term { $$ = $1; }
- | expr'+'expr { $$ = new XAr2( $1, '+', $3 ); }
- | expr'-'expr { $$ = new XAr2( $1, '-', $3 ); }
- | expr'*'expr { $$ = new XAr2( $1, '*', $3 ); }
- | expr'/'expr { $$ = new XAr2( $1, '/', $3 ); }
- | '+'term %prec '*' { $$ = new XAr1( '+', $2 ); }
- | '-'term %prec '*' { $$ = new XAr1( '-', $2 ); }
- ;
- expr : '!' expr { $$ = new XBool1( $2 ); }
- | lxNot expr { $$ = new XBool1( $2 ); }
- | expr lxOr expr { $$ = new XBool2( $1, '|', $3 ); }
- | expr lxAnd expr { $$ = new XBool2( $1, '&', $3 ); }
- | lxNil { $$ = new XImmediate( new CNil ); }
- | lxTrue { $$ = new XImmediate( new CBool( 1 )); }
- | lxFalse { $$ = new XImmediate( new CBool( 0 )); }
-
- | expr '<' expr { $$ = new XComparison( $1, '<', $3 ); }
- | expr '>' expr { $$ = new XComparison( $1, '>', $3 ); }
- | expr '=' expr { $$ = new XComparison( $1, '=', $3 ); }
- | expr lxNe expr { $$ = new XComparison( $1, '~', $3 ); }
- | expr lxGe expr { $$ = new XComparison( $1, '}', $3 ); }
- | expr lxLe expr { $$ = new XComparison( $1, '{', $3 ); }
- | assign { $$ = $1; }
- ;
- boolean : expr { $$ = $1; }
- ;
- term : '('expr')' { $$ = $2; }
- | lxInt { $$ = new XImmediate( new CLong ( $1 )); }
- | lxReal { $$ = new XImmediate( new CDouble( $1 )); }
- | lxString { $$ = new XImmediate( new CString( $1 )); }
- | lxEndl { $$ = new XEndl; }
- | callf { $$ = $1; }
- | array { $$ = $1; }
- | var { $$ = $1; }
- | const { $$ = $1; }
- | lxUser { $$ = UserSym( $1 ); }
- ;
- var : yyVar { $$ = new XVariable( $1 );}
- | var idx { ($$ = new XVariable( $1, &$1->v ))->
- Add( $1 )->Add( $2 ); }
- ;
- const : yyConst { $$ = new XVariable( $1 );}
- | const idx { ($$ = new XVariable( $1, &$1->v ))->
- Add( $1 )->Add( $2 ); }
- ;
- idx : '['expr']' { $$ = $2; }
- | '.' { HideVars = 1; } lxName
- { $$ = new XImmediate( new CString( $3 )); HideVars = 0; }
- ;
- array : '{' { Sets.Push( new XSet ); } elems '}'
- { $$ = (XSet*)Sets.Last(); Sets.Pop(); }
- ;
- elems :
- | elem {}
- | elems','elem {}
- ;
- elem : expr { XSet* s = (XSet*)Sets.Last(); s->Add( $1 ); }
- ;
- fname : yyFunc { $$ = $1; }
- | yyProc { $$ = $1; }
- ;
- func : extern '('
- {
- HideVars = 1;
- FuncTmp = $$ = $1;
- Blocks.Push( FuncTmp );
- if( $1->Defined())
- {
- yyerror("symbol is already defined");
- yyerrok;
- }
- }
- locals
- {
- HideVars=0;
- XBlock *x = new XBlock;
- FuncTmp->Add( x );
- Blocks.Push( x );
- }
- ')' stats lxEnd ';'
- {
- $$ = FuncTmp;
- Blocks.Pop();
- Blocks.Pop();
- }
- ;
- declf : lxFunc { $$ = FuncTmp = new XFunction( 0 ); }
- | lxProc { $$ = FuncTmp = new XFunction( 1 ); }
- ;
- locals :
- | local {}
- | locals','local {}
- ;
- local : lxName { FuncTmp->AddLocal( $1, yyVar ); }
- ;
- callp : yyProc { Calls.Push( new XCall( $1 )); }'(' args ')'
- { $$ = (XCall*)Calls.Last(); Calls.Pop(); }
- ;
- callf : yyFunc { Calls.Push( new XCall( $1 )); }'(' args ')'
- { $$ = (XCall*)Calls.Last(); Calls.Pop(); }
- | '&''('expr')' { XCall *c = new XDynamic(
- $3, &Global->funcs ); Calls.Push( c ); }'(' args ')'
- { $$ = (XCall*)Calls.Last(); Calls.Pop(); }
- ;
- args :
- | arg {}
- | args','arg {}
- ;
- arg : expr { ((XCall*)Calls.Last())->Add( $1 ); }
- | '*'var { ((XCall*)Calls.Last())->Add( $2 ); $2->ref = 1; }
- ;
- extern : declf lxName
- {
- $1->SetName( $2 );
- ($$ = $1)->father = Global;
- Global->funcs.Add( new LexFunc( $$->name, $$,
- $$->isProc ? yyProc : yyFunc ));
- }
- | declf fname
- {
- if( $1->isProc!=$2->isProc )
- {
- yyerror( "conflict with ",$2->name );
- yyerrok;
- }
- delete $1;
- $$ = $2;
- }
- ;
- %%
- char *CalcPlus::pyylval(){ return (char*)&yylval; }
- Token CalcPlus::__name()
- {
- Token t = YLex::__name();
- if( HideVars || t!=lxName )
- return t;
- LexObj* p;
- for( p = Blocks.LastInList; p; p = p->PrevInList )
- LOOKUP(((XBlock*)(((LexRef*)p)->Obj()))->vars, LexVar );
- LOOKUP( Global->funcs, LexFunc );
- LOOKUP( XUserFunction::funcs, LexFunc );
- for( p = Blocks.LastInList; p; p = p->PrevInList )
- LOOKUP(((XBlock*)(((LexRef*)p)->Obj()))->structs, LexStruct );
- return lxName;
- }
-
- Var* CalcPlus::AddVar( const char* s )
- {
- LexVar* o = (LexVar*)(XSEQ->vars( s ));
- if( o )
- return o->data;
- Var *v = new Var( s, DeclType == declConst );
- XSEQ->vars.Add( new LexVar( s, v,
- v->isConst ? yyConst : yyVar ));
- if( StructTmp )
- {
- CArray *a = new CArray( *StructTmp );
- a->structure = new CArray( *a );
- delete v->v;
- v->v = a;
- }
- return v;
- }
-
- Expression* CalcPlus::UserSym( Expression*, Expression* )
- {
- yyerror("user symbols beginning with '@' are not supported");
- return new XImmediate( new CNil );
- }
-
- CalcPlus::CalcPlus( const char* s ) :
- HideVars( 0 ), YLex( s )
- {
- Blocks.Push( Global = new XBlock );
- UserLib();
- }
-
- CalcPlus::~CalcPlus()
- {
- delete Global;
- }
-
- void CalcPlus::print( ostream& o ) const
- {
- XBlock& X = *Global;
- if( X.n )
- o << X << ';' << endl << endl;
- for( LexObj *p = X.funcs.FirstInList;
- p; p = p->NextInList )
- o << (*((LexFunc*)p)->data) << ';' << endl << endl;
- }
-
- CalcPlus::Err()
- {
- if( !errors->isEmpty())
- {
- Errors( cout );
- return 1;
- }
- const Expression* e = Global->LocateError();
- if( e )
- {
- cout << "Error in expression: " << *e << endl;
- return 1;
- }
- return 0;
- }
-
- CalcPlus::Compile()
- {
- yyparse();
- if( Blocks.NumObj != 1 )
- yyerror();
- if( Expression::Debug )
- cout << *this << endl;
- return Err();
- }
-
- CalcPlus::Link()
- {
- XBlock& x = *Global;
- if( StartSym())
- {
- LexObj* o = x.funcs( StartSym() );
- if( !o )
- {
- cerr << "Start symbol is not defined: "
- << StartSym() << endl;
- return 1;
- }
- XFunction* f = ((LexFunc*)o)->data;
- x.Add( new XCall( f ));
- }
- x.Recursion( &Expression::Link );
- LexObj* p;
- for( p = x.funcs.FirstInList; p; p = p->NextInList )
- ((LexFunc*)p)->data->Recursion( &Expression::Link );
- for( p = x.funcs.FirstInList; p; p = p->NextInList )
- {
- XFunction *f = ((LexFunc*)p)->data;
- if( f->flags & Expression::exLink )
- yyerror( "undefined symbol ", f->name );
- if( f->flags & Expression::exArgs )
- yyerror( "wrong number of arguments - ", f->name );
- if( f->flags & Expression::exRet )
- yyerror( "wrong usage of RETURN - ", f->name );
- }
- return Err();
- }
-
- CType* CalcPlus::Call( const char* f, int argc, ... )
- {
- LexObj* o = Global->funcs( f );
- if( !o )
- {
- cerr << "undefined symbol " << f << endl;
- return 0;
- }
- XCall c(((LexFunc*)o)->data );
- va_list l;
- va_start( l, argc );
- for( int i = 0; i < argc; i++ )
- {
- CType *t = va_arg( l, CType* );
- c.Add( new XImmediate( t->copy() ));
- }
- va_end( l );
- c.Link();
- const mask =
- Expression::exLink |
- Expression::exArgs |
- Expression::exRet
- ;
- if( c.flags & mask )
- {
- const Expression *e = c.LocateError( mask );
- if( e )
- cerr << "error in expression " << *e << endl;
- cerr << "linker error, symbol " << f << endl;
- return 0;
- }
- c.father = Global;
- c.Calculate();
- if( c.flags )
- {
- const Expression *e = c.LocateError( Expression::exError );
- if( e )
- cerr << "error in expression " << *e << endl;
- cerr << "interpreter errror" << endl;
- return 0;
- }
- return c.Func->v;
- }
-
- CalcPlus::Exec()
- {
- Global->Calculate();
- return Err();
- }
-
- CalcPlus::Run()
- {
- return Compile() || Link() || Exec();
- }
-
-