From 8bcb83035607371a2326374665e9cc56c662a783 Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Fri, 30 Dec 2011 22:40:21 -0700 Subject: Wow, dictionaries, nested dictionaries, for loops They all work. I still think I should change the lists to arrays in the backend so they can be indexed as well as iterated over and appended to. --- src/astnode.cpp | 1 + src/astnode.h | 1 + src/functiondisplay.cpp | 34 ++++++++++++- src/functiondisplay.h | 3 ++ src/gamebuilder.cpp | 2 +- src/gamestate.cpp | 125 +++++++++++++++++++++++++++++++++++++++++++++--- src/gamestate.h | 4 +- src/main.cpp | 2 +- src/parser.y | 25 ++++++++-- src/variable.cpp | 35 +++++++++++++- src/variable.h | 14 ++++-- test.stage | 92 ++++++++++++++++++++++++----------- 12 files changed, 287 insertions(+), 51 deletions(-) diff --git a/src/astnode.cpp b/src/astnode.cpp index 84f6845..2417968 100644 --- a/src/astnode.cpp +++ b/src/astnode.cpp @@ -45,6 +45,7 @@ Bu::Formatter &operator<<( Bu::Formatter &f, AstNode::Type t ) case AstNode::tReturn: return f << "tReturn"; case AstNode::tAppend: return f << "tAppend"; case AstNode::tInsert: return f << "tInsert"; + case AstNode::tIndex: return f << "tIndex"; case AstNode::tLeafLiteral: return f << "!tLeafLiteral!"; case AstNode::tVarName: return f << "tVarName"; diff --git a/src/astnode.h b/src/astnode.h index 58c4a42..a1215ed 100644 --- a/src/astnode.h +++ b/src/astnode.h @@ -35,6 +35,7 @@ public: tReturn = 0x01000017, tAppend = 0x01000018, tInsert = 0x01000019, + tIndex = 0x0100001A, tLeafLiteral = 0x02000000, tVarName = 0x02000001, diff --git a/src/functiondisplay.cpp b/src/functiondisplay.cpp index fa5b79c..4790844 100644 --- a/src/functiondisplay.cpp +++ b/src/functiondisplay.cpp @@ -15,7 +15,37 @@ FunctionDisplay::~FunctionDisplay() void FunctionDisplay::call( class GameState &gState ) { - Variable v = gState.popDeref(); - sio << "Display: " << v << sio.nl; + Bu::String s = gState.popDeref().to( Variable::tString ).getString(); + + sio << format( s ) << sio.nl; +// sio << "Display: " << v << sio.nl; +} + +Bu::String FunctionDisplay::format( const Bu::String &sSrc ) +{ + Bu::String sRet; + bool bWs = true; + Bu::String::const_iterator i = sSrc.begin(); + + while( i ) + { + for(; i; i++ ) + { + if( *i != ' ' && *i != '\t' && *i != '\n' && *i != '\r' ) + break; + } + for(; i; i++ ) + { + if( i == ' ' || i == '\t' || *i == '\n' || *i == '\r' ) + { + sRet.append(' '); + break; + } + + sRet.append( *i ); + } + } + + return sRet; } diff --git a/src/functiondisplay.h b/src/functiondisplay.h index 3b7e828..48e51fe 100644 --- a/src/functiondisplay.h +++ b/src/functiondisplay.h @@ -11,6 +11,9 @@ public: virtual Bu::String getName() const { return "display"; } virtual void call( class GameState &gState ); + +private: + Bu::String format( const Bu::String &sSrc ); }; #endif diff --git a/src/gamebuilder.cpp b/src/gamebuilder.cpp index 791ba6b..d04a642 100644 --- a/src/gamebuilder.cpp +++ b/src/gamebuilder.cpp @@ -185,7 +185,7 @@ void GameBuilder::closeCommand() { pCurCmd->setAst( pCurRoot ); pCurRoot = pCurNode = NULL; -// pCurCmd->print(); + //pCurCmd->print(); if( bGlobal ) { pGame->csGlobal.addCommand( pCurCmd ); diff --git a/src/gamestate.cpp b/src/gamestate.cpp index e8df070..bd3e638 100644 --- a/src/gamestate.cpp +++ b/src/gamestate.cpp @@ -120,7 +120,7 @@ void GameState::delVariable( const Bu::String &sName, ScopeId id ) throw Bu::ExceptionBase("Really bad scopeid passed into getVariable"); } -Variable GameState::getVariable( const Bu::String &sName, ScopeId id ) +Variable &GameState::getVariable( const Bu::String &sName, ScopeId id ) { try { @@ -174,12 +174,62 @@ void GameState::setVariable( const Bu::String &sName, const Variable &v, throw Bu::ExceptionBase("Really bad scopeid passed into setVariable"); } -Variable GameState::deref( const Variable &src ) +Variable &GameState::deref( Variable &src, bool bCreate ) { if( src.getType() == Variable::tVariable ) { VariableRef r = src.getVariableRef(); - return getVariable( r.sName, r.sid ); + try + { + switch( r.sid ) + { + case sidLocal: + return lsLocal.peek()->get( r.sName ); + + case sidGlobal: + return sGlobal.get( r.sName ); + + case sidPlayer: + return sPlayer.get( r.sName ); + + case sidSituation: + return hsSituation.get( sCurSituation )->get( r.sName ); + } + } + catch( Bu::HashException &e ) + { + if( bCreate ) + { + switch( r.sid ) + { + case sidLocal: + lsLocal.peek()->insert( r.sName, Variable() ); + return lsLocal.peek()->get( r.sName ); + + case sidGlobal: + sGlobal.insert( r.sName, Variable() ); + return sGlobal.get( r.sName ); + + case sidPlayer: + sPlayer.insert( r.sName, Variable() ); + return sPlayer.get( r.sName ); + + case sidSituation: + hsSituation.get( sCurSituation )->insert( r.sName, Variable() ); + return hsSituation.get( sCurSituation )->get( r.sName ); + } + } + else + { + throw Bu::ExceptionBase("No %d variable named %s found.", + r.sid, + r.sName.getStr() ); + } + } + } + else if( src.getType() == Variable::tVarPtr ) + { + return *src.getVariablePtr(); } return src; } @@ -231,6 +281,10 @@ Variable GameState::popDeref() VariableRef r = v.getVariableRef(); return getVariable( r.sName, r.sid ); } + else if( v.getType() == Variable::tVarPtr ) + { + return *v.getVariablePtr(); + } return v; } @@ -294,9 +348,11 @@ void GameState::parse( const AstBranch::NodeList &lCode ) case AstNode::tStore: { Variable y = popDeref(); - Variable dst = pop(); + deref( lStack.peek(), true ) = y; +/* Variable dst = pop(); + VariableRef r = dst.getVariableRef(); - setVariable( r.sName, y, r.sid ); + setVariable( r.sName, y, r.sid ); */ } break; @@ -449,7 +505,7 @@ void GameState::parse( const AstBranch::NodeList &lCode ) case AstNode::tAppend: { Variable v = popDeref(); - lStack.peek() += v; + deref( lStack.peek() ) += v; } break; @@ -457,7 +513,16 @@ void GameState::parse( const AstBranch::NodeList &lCode ) { Variable v = popDeref(); Variable k = popDeref(); - lStack.peek().insert( k, v ); + deref( lStack.peek() ).insert( k, v ); + } + break; + + case AstNode::tIndex: + { + Variable v = popDeref(); + Variable cx = pop(); + Variable &c = deref( cx ); + push( Variable( &c.get( v ) ) ); } break; @@ -505,7 +570,53 @@ void GameState::parse( const AstBranch::NodeList &lCode ) break; case AstNode::tForEach: + { + AstBranch::NodeList lFe = + dynamic_cast(*i)->getNodeList(); + AstBranch::NodeList::const_iterator iEach = lFe.begin(); + AstBranch::NodeList::const_iterator iIn = iEach+1; + AstBranch::NodeList::const_iterator iDo = iIn+1; + + const AstBranch::NodeList &lEachVrs = + dynamic_cast(*iEach)->getNodeList(); + AstBranch::NodeList::const_iterator iEachVrs = lEachVrs.begin(); + + bool bUseKey = false; + VariableRef vrKey, vrValue; + if( lEachVrs.getSize() == 2 ) + { + vrKey = dynamic_cast(*iEachVrs)-> + getValue().getVariableRef(); + iEachVrs++; + vrValue = dynamic_cast(*iEachVrs)-> + getValue().getVariableRef(); + bUseKey = true; + } + else + { + vrValue = dynamic_cast(*iEachVrs)-> + getValue().getVariableRef(); + } + + parse( dynamic_cast(*iIn)->getNodeList() ); + Variable vIn = popDeref(); + + const AstBranch::NodeList &rDo = + dynamic_cast(*iDo)->getNodeList(); + if( vIn.getType() == Variable::tDictionary ) + { + const Variable::VariableHash &rHash = vIn.getHash(); + for( Variable::VariableHash::const_iterator i = + rHash.begin(); i; i++ ) + { + if( bUseKey ) + setVariable( vrKey.sName, i.getKey(), vrKey.sid ); + setVariable( vrValue.sName, i.getValue(), vrValue.sid ); + parse( rDo ); + } + } + } break; case AstNode::tWhile: diff --git a/src/gamestate.h b/src/gamestate.h index e32eeaa..5c47ce0 100644 --- a/src/gamestate.h +++ b/src/gamestate.h @@ -29,10 +29,10 @@ public: bool hasVariable( const Bu::String &sName, ScopeId id ); void delVariable( const Bu::String &sName, ScopeId id ); - Variable getVariable( const Bu::String &sName, ScopeId id=sidLocal ); + Variable &getVariable( const Bu::String &sName, ScopeId id=sidLocal ); void setVariable( const Bu::String &sName, const Variable &v, ScopeId id=sidLocal ); - Variable deref( const Variable &src ); + Variable &deref( Variable &src, bool bCreate=false ); Bu::StringList tokenize( const Bu::String &sSrc ); void exit(); diff --git a/src/main.cpp b/src/main.cpp index 413151a..b3dbba7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -36,7 +36,7 @@ int main( int argc, char *argv[] ) while( gs.isRunning() ) { char buf[1024]; - sio << "command> " << sio.flush; + sio << sio.nl << "command> " << sio.flush; fgets( buf, 1024, stdin ); gs.execCommand( buf ); diff --git a/src/parser.y b/src/parser.y index 707d85d..3dfd737 100644 --- a/src/parser.y +++ b/src/parser.y @@ -155,7 +155,19 @@ cmpltExpr: expr ';' | tokReturn '(' ')' ';' { bld.addNode( AstNode::tReturn ); } | tokGoto '(' expr ')' ';' { bld.addNode( AstNode::tGoto ); } | ifbase - | tokFor tokEach forIterator tokIn expr tokDo '{' cmpltExprList '}' + | tokFor tokEach { + bld.addNode( AstNode::tForEach ); + bld.addNode( AstNode::tScope ); + } forIterator tokIn { + bld.closeNode(); + bld.addNode( AstNode::tScope ); + } expr tokDo '{' { + bld.closeNode(); + bld.addNode( AstNode::tScope ); + } cmpltExprList '}' { + bld.closeNode(); + bld.closeNode(); + } | tokWhile { bld.addNode( AstNode::tWhile ); bld.addNode( AstNode::tScope ); @@ -168,8 +180,12 @@ cmpltExpr: expr ';' } ; -forIterator: tokIdent - | tokIdent ':' tokIdent +forIterator: tokIdent { bld.addVarRef( *($1), sidLocal ); } + | tokIdent ':' tokIdent { + bld.addVarRef( *($1), sidLocal ); + bld.addVarRef( *($3), sidLocal ); + } + ; ifbase: tokIf { bld.addNode( AstNode::tIf ); @@ -226,7 +242,8 @@ expr: literal | expr tokLtEq expr { bld.addNode( AstNode::tCompLtEq ); } | expr tokGtEq expr { bld.addNode( AstNode::tCompGtEq ); } | '(' expr ')' - | expr '[' expr ']' + | expr '[' expr ']' { bld.addNode( AstNode::tIndex ); } + | expr '[' expr ']' '=' expr { bld.addNode( AstNode::tInsert ); } | '[' ']' { bld.addLiteral( Variable( Variable::tList ) ); } | '[' { bld.addLiteral( Variable( Variable::tList ) ); } listValues ']' | '{' '}' { bld.addLiteral( Variable( Variable::tDictionary ) ); } diff --git a/src/variable.cpp b/src/variable.cpp index 1e5cc9b..1100c84 100644 --- a/src/variable.cpp +++ b/src/variable.cpp @@ -55,6 +55,12 @@ Variable::Variable( const Bu::String &sValue ) : this->sValue = new Bu::String( sValue ); } +Variable::Variable( Variable *pValue ) : + eType( tVarPtr ), + pValue( pValue ) +{ +} + Variable::~Variable() { deinitType(); @@ -102,6 +108,16 @@ VariableRef Variable::getVariableRef() const return *rValue; } +Variable *Variable::getVariablePtr() const +{ + return pValue; +} + +const Variable::VariableHash &Variable::getHash() const +{ + return *hValue; +} + Variable Variable::to( Type e ) const { if( e == eType ) @@ -227,6 +243,14 @@ bool Variable::has( const Variable &vKey ) throw Bu::ExceptionBase("Insert on non-dictionary."); } +Variable &Variable::get( const Variable &vKey ) +{ + if( eType == tDictionary ) + return hValue->get( vKey ); + else + throw Bu::ExceptionBase("Insert on non-dictionary."); +} + Variable &Variable::operator=( const Variable &rhs ) { deinitType(); @@ -266,6 +290,10 @@ Variable &Variable::operator=( const Variable &rhs ) case tDictionary: (*hValue) = *rhs.hValue; break; + + case tVarPtr: + pValue = rhs.pValue; + break; } } @@ -725,11 +753,11 @@ void Variable::initType() break; case tList: - lValue = new VList(); + lValue = new VariableList(); break; case tDictionary: - hValue = new VHash(); + hValue = new VariableHash(); break; } } @@ -821,6 +849,9 @@ Bu::Formatter &operator<<( Bu::Formatter &f, const Variable &v ) case Variable::tDictionary: return f << *v.hValue; + + case Variable::tVarPtr: + return f << "(varptr:" << *v.pValue << ")"; } return f << "ERROR"; diff --git a/src/variable.h b/src/variable.h index 97308c7..22a1b26 100644 --- a/src/variable.h +++ b/src/variable.h @@ -44,23 +44,30 @@ public: Variable( double fValue ); Variable( bool bValue ); Variable( const Bu::String &sValue ); + Variable( Variable *pValue ); virtual ~Variable(); static Variable newSituationName( const Bu::String &s ); static Variable newVariableName( const Bu::String &s, ScopeId sid ); Type getType() const { return eType; } + + typedef Bu::List VariableList; + typedef Bu::Hash VariableHash; bool getBool() const; int64_t getInt() const; double getFloat() const; Bu::String getString() const; VariableRef getVariableRef() const; + Variable *getVariablePtr() const; + const VariableHash &getHash() const; Variable to( Type e ) const; void insert( const Variable &vKey, const Variable &vValue ); bool has( const Variable &vKey ); + Variable &get( const Variable &vKey ); Variable &operator=( const Variable &rhs ); Variable &operator+=( const Variable &rhs ); @@ -86,17 +93,14 @@ private: private: Type eType; - typedef Bu::List VList; - typedef Bu::Hash VHash; - union { int64_t iValue; double fValue; bool bValue; Bu::String *sValue; - VList *lValue; - VHash *hValue; + VariableList *lValue; + VariableHash *hValue; VariableRef *rValue; Variable *pValue; }; diff --git a/test.stage b/test.stage index ff159ff..00e7d94 100644 --- a/test.stage +++ b/test.stage @@ -7,10 +7,44 @@ game.start = <>; global { - command: "eat" object + command: "go" dir { - display(object); + if exists(situation.exits) then + { + if dir in situation.exits then + { + goto( situation.exits[dir] ); + } + } + display('''You're not really sure how to do that...'''); + } + + command: "exits" + { + if exists(situation.exits) then + { + out = "Obvious exits are: "; + bFirst = true; + for each dir : dest in situation.exits do + { + if bFirst then + { + bFirst = false; + } + else + { + out += ", "; + } + out += dir; + } + display( out ); + } + else + { + display("There are no obvious exits."); + } } + // You should always have a global exit, quit, escape, something for // dev-testing at least. command: "exit" @@ -50,54 +84,58 @@ function getThing() situation <> { - command: "go" "home" + setup { - display("Home would be nice..."); + goto( <> ); } - command: "go" elsewhere + enter { - display("You don't know how to go " + elsewhere ); } +} + +situation <> +{ setup { - stuff = {"things": 55, 112: "Bob"}; - display( stuff ); - display( 113 - 1 in stuff ); - exit(); + situation.exits = { + 'south': <>, + 'east': <> + }; } - enter { - display('''This is the enter part of the start situation'''); + display('''You are in the dining room, it's very nice and warm. There + is a big table and...stuff. Looks like the living room is south, and + the kitchen is to the east.'''); } } -situation <> +situation <> { - command: "eat" object + setup { - display("You can't eat " + object ); + situation.exits = { + 'north': <> + }; } - - command: "eat" object "now" + enter { - display("Alright, fine, eat " + object + " now..." ); + display('''Living room!'''); } +} +situation <> +{ setup { - situation.thing = "Just a thing"; + situation.exits = { + 'west': <> + }; } + enter { - getThing(); - display('''Entered stuff''' + player.name); - count = 0; - while count < 5 do - { - display('thing to count!'); - count += 1; - } + display('''Kitchen!'''); } } -- cgit v1.2.3