📄 gsm.cc
字号:
//// $Source: /home/gambit/CVS/gambit/sources/gcl/gsm.cc,v $// $Date: 2002/08/27 18:57:17 $// $Revision: 1.5 $//// DESCRIPTION:// Implementation of GSM environment//// This file is part of Gambit// Copyright (c) 2002, The Gambit Project//// 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.//class Portion;class CallFuncObj;class RefHashTable;#include "base/base.h"#include "gsm.h"#include "portion.h"#include "gsmhash.h"#include "gsmfunc.h"#include "gsminstr.h"#include "game/nfg.h"#include "nash/mixedsol.h"#include "nash/behavsol.h"#include "game/efbasis.h"//----------------------------------------------------------------// declaration of the game reference counter//----------------------------------------------------------------RefCountHashTable< void* > GSM::_GameRefCount;int& GSM::GameRefCount(void* game){ if(_GameRefCount.IsDefined(game)) return _GameRefCount(game); else { _GameRefCount.Define(game, 0); return _GameRefCount(game); }}//----------------------------------------------------------------// function list sorting functions//----------------------------------------------------------------class gFuncListSorter : public gListSorter<gclFunction*>{protected: bool LessThan(gclFunction* const& a, gclFunction* const& b) const { return (a->FuncName() > b->FuncName()); }public: gFuncListSorter(void) { }};class gTextListSorter : public gListSorter<gText>{protected: bool LessThan(gText const& a, gText const& b) const { return (a > b); }public: gTextListSorter(void) { }};//--------------------------------------------------------------------// implementation of GSM (Stack machine)//--------------------------------------------------------------------int GSM::_NumObj = 0;GSM::GSM(gInput& s_in, gOutput& s_out, gOutput& s_err) : _StdIn(s_in), _StdOut(s_out), _StdErr(s_err){ // global function default variables initialization // these should be done before InitFunctions() is called _RefTableStack = new gStack< RefHashTable* >(1); _RefTableStack->Push(new RefHashTable); _FuncNameStack = new gStack< gText >; _FuncTable = new FunctionHashTable; InitFunctions(); // This function is located in gsmfunc.cc _NumObj++;}GSM::~GSM(){ _NumObj--; delete _FuncTable; while (_RefTableStack->Depth()) delete _RefTableStack->Pop(); delete _RefTableStack; delete _FuncNameStack;}bool GSM::VarIsDefined(const gText &p_name) const{ if (p_name == "") throw gclRuntimeError("Tried to see if empty variable name defined"); else if (p_name[0u] == '$') { if (p_name[1u] == '$') return _GlobalRefTable.IsDefined(p_name.Right(p_name.Length() - 2)); else return _GlobalRefTable.IsDefined(UserFuncName() + gText((char) 1) + p_name.Right(p_name.Length() - 1)); } return _RefTableStack->Peek()->IsDefined(p_name);}void GSM::VarDefine(const gText& var_name, Portion* p){ bool type_match = true; Portion *old_value = 0; if (var_name == "") throw gclRuntimeError("Tried to define empty variable name"); _ResolveRef(p); if (var_name[0u] == '$') { gText global_name; if (var_name[1u] != '$') global_name = (UserFuncName() + gText((char) 1) + var_name.Right(var_name.Length() - 1)); else global_name = var_name.Right(var_name.Length() - 2); if (_GlobalRefTable.IsDefined(global_name)) { old_value = _GlobalRefTable(global_name); if (p->Spec().ListDepth > 0) { if (((ListPortion*) old_value)->Spec().Type != ((ListPortion*) p)->Spec().Type) { if (((ListPortion*) p)->Spec().Type == porUNDEFINED) ((ListPortion*) p)->SetDataType(old_value->Spec().Type); else if (old_value->Spec().Type != porUNDEFINED) type_match = false; } } else { PortionSpec ospec = old_value->Spec(); PortionSpec pspec = p->Spec(); if (ospec.Type == porNULL) ospec = ((NullPortion*) old_value)->DataType(); if (pspec.Type == porNULL) pspec = ((NullPortion*) p)->DataType(); if (ospec.Type != pspec.Type) if (!PortionSpecMatch(ospec, pspec)) type_match = false; } } if (!type_match) { delete p; throw gclRuntimeError("Cannot change the type of variable \"" + var_name + "\""); } else { if (old_value) delete _VarRemove(var_name); _GlobalRefTable.Define(global_name, p); } } else { if (_RefTableStack->Peek()->IsDefined(var_name)) { old_value = (*_RefTableStack->Peek())(var_name); if (p->Spec().ListDepth > 0) { if (((ListPortion*) old_value)->Spec().Type != ((ListPortion*) p)->Spec().Type) { if (((ListPortion*) p)->Spec().Type == porUNDEFINED) ((ListPortion*) p)->SetDataType(old_value->Spec().Type); else if (old_value->Spec().Type != porUNDEFINED) type_match = false; } } else { PortionSpec ospec = old_value->Spec(); PortionSpec pspec = p->Spec(); if (ospec.Type == porNULL) ospec = ((NullPortion*) old_value)->DataType(); if (pspec.Type == porNULL) pspec = ((NullPortion*) p)->DataType(); if (ospec.Type != pspec.Type) if (!PortionSpecMatch(ospec, pspec)) type_match = false; } } if (!type_match) { delete p; throw gclRuntimeError("Cannot change the type of variable \"" + var_name + "\""); } else { if (old_value) delete _VarRemove(var_name); _RefTableStack->Peek()->Define(var_name, p); } }}Portion* GSM::VarValue(const gText &p_name) const{ if (p_name == "") throw gclRuntimeError("Tried to get value of empty variable name"); else if (p_name[0u] == '$') { if (p_name[1u] == '$') return _GlobalRefTable(p_name.Right(p_name.Length() - 2)); else return _GlobalRefTable(UserFuncName() + gText((char) 1) + p_name.Right(p_name.Length() - 1)); } return (*_RefTableStack->Peek())(p_name);}Portion* GSM::_VarRemove(const gText &p_name){ if (p_name == "") throw gclRuntimeError("Tried to remove empty variable name"); else if (p_name[0u] == '$') { if (p_name[1u] == '$') return _GlobalRefTable.Remove(p_name.Right(p_name.Length() - 2)); else return _GlobalRefTable.Remove(UserFuncName() + gText((char) 1) + p_name.Right(p_name.Length() - 1)); } return _RefTableStack->Peek()->Remove(p_name);}//---------------------------------------------------------------------// Reference related functions//---------------------------------------------------------------------Portion* GSM::Assign( Portion* p1, Portion* p2 ){ Portion* result = 0; gText varname; if(p1->Spec().Type == porREFERENCE) varname = ((ReferencePortion*) p1)->Value(); _ResolveRef( p2 ); _ResolveRef( p1 ); PortionSpec p1Spec(p1->Spec()); PortionSpec p2Spec(p2->Spec()); if(p1->Original() == p2->Original()) // assigning a variable to itself { delete p2; result = p1; } else if(p2Spec.Type == porREFERENCE) // assigning from undefined variable { throw gclRuntimeError("Undefined variable " + ((ReferencePortion *) p2)->Value()); } else if(p1Spec.Type == porREFERENCE) // assigning to a new variable { delete p1; if( p2->IsReference() ) { VarDefine( varname, p2->ValCopy() ); delete p2; } else VarDefine( varname, p2 ); result = VarValue( varname )->RefCopy(); } else if( p1Spec == p2Spec && p1Spec.Type != porNULL && !(p1Spec.Type & porMIXED) && !(p1Spec.Type & porBEHAV) ) { if(p1Spec.ListDepth == 0) // not a list { result = p1; switch (p1Spec.Type) { case porNUMBER: ((NumberPortion*) p1)->SetValue(((NumberPortion*) p2)->Value()); break; case porTEXT: ((TextPortion*) p1)->SetValue(((TextPortion*) p2)->Value()); break; case porBOOLEAN: ((BoolPortion*) p1)->SetValue(((BoolPortion*) p2)->Value()); break; case porEFOUTCOME: ((EfOutcomePortion *) p1)->SetValue(((EfOutcomePortion *) p2)->Value()); break; case porNFOUTCOME: ((NfOutcomePortion *) p1)->SetValue(((NfOutcomePortion *) p2)->Value()); break; case porNFSUPPORT: ((NfSupportPortion *) p1)->SetValue(new NFSupport(*((NfSupportPortion *) p2)->Value())); break; case porEFSUPPORT: ((EfSupportPortion *) p1)->SetValue(new EFSupport(*((EfSupportPortion *) p2)->Value())); break; case porEFBASIS: ((EfBasisPortion *) p1)->SetValue(new EFBasis(*((EfBasisPortion *) p2)->Value())); break; case porINFOSET: ((InfosetPortion *) p1)->SetValue(((InfosetPortion *) p2)->Value()); break; case porNFPLAYER: ((NfPlayerPortion *) p1)->SetValue(((NfPlayerPortion *) p2)->Value()); break; case porEFPLAYER: ((EfPlayerPortion *) p1)->SetValue(((EfPlayerPortion *) p2)->Value()); break; case porSTRATEGY: ((StrategyPortion *) p1)->SetValue(((StrategyPortion *) p2)->Value()); break; case porNODE: ((NodePortion *) p1)->SetValue(((NodePortion *) p2)->Value()); break; case porACTION: ((ActionPortion *) p1)->SetValue((Action *)((ActionPortion *) p2)->Value()); break; case porNFG: ((NfgPortion *) p1)->SetValue(((NfgPortion *) p2)->Value()); break; case porEFG: ((EfgPortion *) p1)->SetValue(((EfgPortion *) p2)->Value()); break; case porINPUT: case porOUTPUT: delete p1; throw gclRuntimeError("Cannot assign from INPUT/OUTPUT variable" ); default: throw gclRuntimeError("Assigning to unknown type " + PortionSpecToText(p1Spec)); } delete p2; // result already assigned on top of this block } // both p1 and p2 are lists else if((p1Spec.Type == p2Spec.Type) || (p1Spec.Type == porUNDEFINED)) { if(!(p1Spec.Type & (porINPUT|porOUTPUT))) { ((ListPortion*) p1)->AssignFrom(p2); delete p2; result = p1; } else // error: assigning to (list of) INPUT or OUTPUT { delete p2; delete p1; throw gclRuntimeError("Cannot assign from INPUT/OUTPUT variable" ); } } else // error: changing the type of a list { delete p2; delete p1; throw gclRuntimeError("Cannot change list type"); } } else if(varname != "") // make sure variable is associated with a var name { if(p1Spec.Type == porNULL) p1Spec = ((NullPortion*) p1)->DataType(); if(p2Spec.Type == porNULL) p2Spec = ((NullPortion*) p2)->DataType(); if(PortionSpecMatch(p1Spec, p2Spec) || (p1Spec.Type == porUNDEFINED && p1Spec.ListDepth > 0 && p2Spec.ListDepth > 0)) { delete p1; if( p2->IsReference() ) { VarDefine( varname, p2->ValCopy() ); delete p2; } else VarDefine( varname, p2 ); result = VarValue( varname )->RefCopy(); } else { // error: changing the type of variable delete p2; delete p1; throw gclRuntimeError("Cannot change the type of variable \"" + varname + "\" from " + PortionSpecToText(p1Spec) + " to " + PortionSpecToText(p2Spec)); } } else { delete p2; delete p1; throw gclRuntimeError("Must assign to a variable"); } return result;}bool GSM::UnAssign(Portion *p){ if (p->Spec().Type == porREFERENCE) { if(VarIsDefined(((ReferencePortion*) p)->Value())) { delete _VarRemove(((ReferencePortion *) p)->Value()); delete p; return true; } else { delete p; return true; } } else { throw gclRuntimeError("UnAssign[] called on a non-reference value"); }}Portion* GSM::UnAssignExt(Portion *p){ gText txt; if(p->Spec().Type == porREFERENCE) { gText varname = ((ReferencePortion*) p)->Value(); if(VarIsDefined( varname ) ) { delete p; delete _VarRemove( varname ); return new BoolPortion(triTRUE); } else { delete p; return new BoolPortion(triFALSE); } } else { throw gclRuntimeError("UnAssign[] called on a non-reference value"); }}bool GSM::VarRemove(const gText& var_name){ if(VarIsDefined(var_name)) _VarRemove(var_name); return true;}//-----------------------------------------------------------------------// _ResolveRef functions//-----------------------------------------------------------------------void GSM::_ResolveRef(Portion *&p){ if (p->Spec().Type == porREFERENCE) { gText ref = ((ReferencePortion*) p)->Value(); if (VarIsDefined(ref)) { Portion *result = VarValue(ref)->RefCopy(); delete p; p = result; } }}//-------------------------------------------------------------------// CallFunction() related functions//-------------------------------------------------------------------bool GSM::AddFunction(gclFunction* func){ gclFunction *old_func; bool result; if (func == 0) return false; if(!_FuncTable->IsDefined(func->FuncName())) { _FuncTable->Define(func->FuncName(), func); return true; } else { old_func = (*_FuncTable)(func->FuncName()); result = old_func->Combine(func); if (!result) throw gclRuntimeError("New " + old_func->FuncName() + "[] ambiguous with existing function"); return result; }}bool GSM::DeleteFunction(gclFunction* func){ gclFunction *old_func = 0; if (func == 0) return 0; if (!_FuncTable->IsDefined(func->FuncName())) { throw gclRuntimeError("Function " + old_func->FuncName() + " not found"); } else { old_func = (*_FuncTable)(func->FuncName()); if (!old_func->Delete(func)) throw gclRuntimeError("No matching prototype found"); } return true;}//----------------------------------------------------------------------------// Execute function//----------------------------------------------------------------------------Portion *GSM::Execute(gclExpression *expr, bool /*user_func*/){ return expr->Evaluate(*this);}Portion* GSM::ExecuteUserFunc(gclExpression& program, const gclSignature& func_info, Portion** param, const gText& funcname ){ Portion *result, *result_copy;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -