cmd.cc

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2008 Kamil Dudka <xdudka00@stud.fit.vutbr.cz>
00003  *
00004  * This file is part of vyp08 (compiler and interpreter of VYP08 language).
00005  *
00006  * vyp08 is free software: you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation, either version 3 of the License, or
00009  * any later version.
00010  *
00011  * vyp08 is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with vyp08.  If not, see <http://www.gnu.org/licenses/>.
00018  */
00019 
00020 #include "config.h"
00021 #include "cmd.h"
00022 
00023 #include "vypIO.h"
00024 
00025 using namespace StreamDecorator;
00026 using std::string;
00027 
00029 class PushValueCmd: public ICmd {
00030     public:
00031         PushValueCmd(const Token &t, PValue val): t_(t), val_(val) { }
00032         virtual void toStream(std::ostream &str) const {
00033             str << Color(C_LIGHT_CYAN) << "PUSH_VALUE_CMD" << Color(C_NO_COLOR)
00034                 << "(" << t_ << ")";
00035         }
00036         virtual bool exec(FncDefinition *fnc) {
00037             return fnc->vm->vmStack.push(val_, t_);
00038         }
00039     private:
00040         Token   t_;
00041         PValue  val_;
00042 };
00043 
00045 class ReturnCmd: public ICmd {
00046     public:
00047         ReturnCmd(const Token &t, bool push): t_(t), push_(push) { }
00048         virtual void toStream(std::ostream &str) const {
00049             str << Color(C_LIGHT_CYAN)
00050                 << (push_ ? "PUSH_RETURN_CMD" : "POP_RETURN_CMD")
00051                 << Color(C_NO_COLOR)
00052                 << "(" << t_ << ")";
00053         }
00054         virtual bool exec(FncDefinition *fnc) {
00055             return push_ ?
00056                 fnc->vm->vmStack.pushFromVar(fnc->self, t_):
00057                 fnc->vm->vmStack.popToVar(fnc->self, t_);
00058         }
00059     private:
00060         Token   t_;
00061         bool    push_;
00062 };
00063 
00065 class GlVarCmd: public ICmd {
00066     public:
00067         GlVarCmd(const Token &t, bool push): t_(t), push_(push) { }
00068         virtual void toStream(std::ostream &str) const {
00069             str << Color(C_LIGHT_CYAN)
00070                 << (push_ ? "PUSH_GL_VAR_CMD" : "POP_GL_VAR_CMD")
00071                 << Color(C_NO_COLOR)
00072                 << "(" << t_ << ")";
00073         }
00074         virtual bool exec(FncDefinition *fnc) {
00075             Vm *vm = fnc->vm;
00076             Var &var = *(vm->glVars[t_.text]);
00077             return push_ ?
00078                 fnc->vm->vmStack.pushFromVar(var, t_):
00079                 fnc->vm->vmStack.popToVar(var, t_);
00080         }
00081     private:
00082         Token   t_;
00083         bool    push_;
00084 };
00085 
00087 class LcVarCmd: public ICmd {
00088     public:
00089         LcVarCmd(const Token &t, bool push): t_(t), push_(push) { }
00090         virtual void toStream(std::ostream &str) const {
00091             str << Color(C_LIGHT_CYAN)
00092                 << (push_ ? "PUSH_LC_VAR_CMD" : "POP_LC_VAR_CMD")
00093                 << Color(C_NO_COLOR)
00094                 << "(" << t_ << ")";
00095         }
00096         virtual bool exec(FncDefinition *fnc) {
00097             Var &var = *(fnc->vars[t_.text]);
00098             return push_ ?
00099                 fnc->vm->vmStack.pushFromVar(var, t_):
00100                 fnc->vm->vmStack.popToVar(var, t_);
00101         }
00102     private:
00103         Token   t_;
00104         bool    push_;
00105 };
00106 
00108 class ArgCmd: public ICmd {
00109     public:
00110         ArgCmd(const Token &t, bool push): t_(t), push_(push) { }
00111         virtual void toStream(std::ostream &str) const {
00112             str << Color(C_LIGHT_CYAN)
00113                 << (push_ ? "PUSH_ARG_CMD" : "POP_ARG_CMD")
00114                 << Color(C_NO_COLOR)
00115                 << "(" << t_ << ")";
00116         }
00117         virtual bool exec(FncDefinition *fnc) {
00118             Var &var = *(fnc->args[t_.text]);
00119             return push_ ?
00120                 fnc->vm->vmStack.pushFromVar(var, t_):
00121                 fnc->vm->vmStack.popToVar(var, t_);
00122         }
00123     private:
00124         Token   t_;
00125         bool    push_;
00126 };
00127 
00129 class UnaryCmd: public ICmd {
00130     public:
00131         UnaryCmd(const Token &t):
00132             t_(t)
00133         {
00134             t_.text.clear();
00135         }
00136         virtual void toStream(std::ostream &str) const {
00137             str << Color(C_LIGHT_CYAN) << "UNARY_CMD"
00138                 << Color(C_NO_COLOR) << "(" << t_ << ")";
00139         }
00140         virtual bool exec(FncDefinition *fnc);
00141     private:
00142         Token t_;
00143 };
00144 
00146 class BinaryCmd: public ICmd {
00147     public:
00148         BinaryCmd(const Token &t):
00149             t_(t)
00150         {
00151             t_.text.clear();
00152         }
00153         virtual void toStream(std::ostream &str) const {
00154             str << Color(C_LIGHT_CYAN) << "BINARY_CMD"
00155                 << Color(C_NO_COLOR) << "(" << t_ << ")";
00156         }
00157         virtual bool exec(FncDefinition *fnc);
00158         bool chkTypes(Value::VType, Value::VType);
00159     private:
00160         Token t_;
00161         int cmp(PConstValue, PConstValue);
00162         void aluOp(PValue, PConstValue);
00163         bool divide(PValue, PConstValue);
00164 };
00165 
00167 class IfCmd: public ICmd {
00168     public:
00169         IfCmd(const Token &t, PCmd ifCmd, PCmd elseCmd):
00170             t_(t), ifCmd_(ifCmd), elseCmd_(elseCmd)
00171         {
00172             t_.text.clear();
00173         }
00174         virtual void toStream(std::ostream &str) const {
00175             str << Color(C_LIGHT_RED) << "IF_CMD"
00176                 << Color(C_NO_COLOR) << "(" << t_ << ")";
00177             str << Color(C_LIGHT_BLUE) << "[[" << Color(C_NO_COLOR);
00178             ifCmd_->toStream(str);
00179             str << Color(C_LIGHT_BLUE) << "]] " << Color(C_NO_COLOR)
00180                 << Color(C_LIGHT_RED) << "else" << Color(C_NO_COLOR)
00181                 << Color(C_LIGHT_BLUE) << " [[" << Color(C_NO_COLOR);
00182             elseCmd_->toStream(str);
00183             str << Color(C_LIGHT_BLUE) << "]]" << Color(C_NO_COLOR);
00184         }
00185         virtual bool exec(FncDefinition *fnc);
00186     private:
00187         Token       t_;
00188         PCmd        ifCmd_;
00189         PCmd        elseCmd_;
00190 };
00191 
00193 class WhileCmd: public ICmd {
00194     public:
00195         WhileCmd(const Token &t, PCmd whileExpr, PCmd whileStat):
00196             t_(t), whileExpr_(whileExpr), whileStat_(whileStat)
00197         {
00198             t_.text.clear();
00199         }
00200         virtual void toStream(std::ostream &str) const {
00201             str << Color(C_LIGHT_RED) << "WHILE_CMD"
00202                 << Color(C_NO_COLOR) << "(" << t_ << ")";
00203             str << Color(C_LIGHT_BLUE) << "[[" << Color(C_NO_COLOR);
00204             whileExpr_->toStream(str);
00205             str << Color(C_LIGHT_BLUE) << "]] " << Color(C_NO_COLOR)
00206                 << Color(C_LIGHT_RED) << "while" << Color(C_NO_COLOR)
00207                 << Color(C_LIGHT_BLUE) << " [[" << Color(C_NO_COLOR);
00208             whileStat_->toStream(str);
00209             str << Color(C_LIGHT_BLUE) << "]]" << Color(C_NO_COLOR);
00210         }
00211         virtual bool exec(FncDefinition *fnc);
00212     private:
00213         Token       t_;
00214         PCmd        whileExpr_;
00215         PCmd        whileStat_;
00216 };
00217 
00219 class CallCmd: public ICmd {
00220     public:
00221         CallCmd(const Token &t, unsigned nArgs, bool pushResult):
00222             t_(t), nArgs_(nArgs), pushResult_(pushResult)
00223         {
00224         }
00225         virtual void toStream(std::ostream &str) const {
00226             str << Color(C_LIGHT_RED) << "CALL_CMD" << Color(C_NO_COLOR)
00227                 << "(" << t_ << ")[" << nArgs_ << "]";
00228             if (pushResult_)
00229                 str << "/" << Color(C_LIGHT_RED) << "PUSH_RESULT" << Color(C_NO_COLOR);
00230         }
00231         virtual bool exec(FncDefinition *fnc);
00232     private:
00233         Token       t_;
00234         unsigned    nArgs_;
00235         bool        pushResult_;
00236 };
00237 
00239 class PrintCmd: public ICmd {
00240     public:
00241         PrintCmd(const Token &t, Value::VType type):
00242             t_(t)
00243         {
00244             var_.value.type = type;
00245         }
00246         virtual void toStream(std::ostream &str) const {
00247             str << Color(C_LIGHT_RED) << "PRINT_CMD" << Color(C_NO_COLOR)
00248                 << "(" << t_ << ")[" << var_.value.type << "]";
00249         }
00250         virtual bool exec(FncDefinition *fnc);
00251     private:
00252         Token           t_;
00253         Var             var_;
00254 };
00255 
00257 class InputCmd: public ICmd {
00258     public:
00259         InputCmd(const Token &t, Value::VType type, bool pushValue):
00260             t_(t), type_(type), pushValue_(pushValue)
00261         {
00262         }
00263         virtual void toStream(std::ostream &str) const {
00264             str << Color(C_LIGHT_RED) << "INPUT_CMD" << Color(C_NO_COLOR)
00265                 << "(" << t_ << ")[" << type_ << "]";
00266         }
00267         virtual bool exec(FncDefinition *fnc);
00268     private:
00269         Token           t_;
00270         Value::VType    type_;
00271         bool            pushValue_;
00272 };
00273 
00274 
00275 // /////////////////////////////////////////////////////////////////////////////
00276 // CmdFactory implementation
00277 struct CmdFactory::Private {
00278     Vm          *const vm;
00279     Private(Vm *vm_):
00280         vm(vm_)
00281     {
00282     }
00283 };
00284 CmdFactory::CmdFactory(Vm *vm):
00285     d(new Private(vm))
00286 {
00287 }
00288 CmdFactory::~CmdFactory() {
00289     delete d;
00290 }
00291 
00292 PCmd CmdFactory::createAssign(Token token, FncDefinition *fnc, VType &dstType) {
00293     if (token.type != ETOKEN_ID) {
00294         std::cerr << Error(E_ERROR, d->vm->fileName, "unexpected token type in assignment", token, true) << std::endl;
00295         return PCmd();
00296     }
00297     const string &name = token.text;
00298 
00299     if (name == fnc->self.name) {
00300         // ID resolved as return value of calling function
00301         if (fnc->self.value.type == Value::V_NULL) {
00302             std::cerr << Error(E_ERROR, d->vm->fileName, "return statement in void function", token) << std::endl;
00303             return PCmd();
00304         } else {
00305             dstType = fnc->self.value.type;
00306             return PCmd(new ReturnCmd(token, false));
00307         }
00308     }
00309 
00310     PVar arg = fnc->args[name];
00311     if (arg) {
00312         // ID resolved as argument of calling function
00313         dstType = arg->value.type;
00314         return PCmd(new ArgCmd(token, false));
00315     }
00316 
00317     PVar lcVar = fnc->vars[name];
00318     if (lcVar) {
00319         // ID resolved as local variable of calling function
00320         dstType = lcVar->value.type;
00321         return PCmd(new LcVarCmd(token, false));
00322     }
00323 
00324     PVar glVar = d->vm->glVars[name];
00325     if (glVar) {
00326         // ID resolved as global variable
00327         dstType = glVar->value.type;
00328         return PCmd(new GlVarCmd(token, false));
00329     }
00330 
00331     // ID not resolved
00332     std::cerr << Error(E_ERROR, d->vm->fileName, "unknown identifier in L-Value", token) << std::endl;
00333     return PCmd();
00334 }
00335 
00336 PCmd CmdFactory::createPush(Token token, FncDefinition *fnc, VType &dstType) {
00337     switch (token.type) {
00338         case ETOKEN_NUMBER_INT:
00339             dstType = Value::V_INT;
00340             return PCmd(new PushValueCmd(token, ValueFactory::create(token.numberInt)));
00341 
00342         case ETOKEN_NUMBER_DOUBLE:
00343             dstType = Value::V_DOUBLE;
00344             return PCmd(new PushValueCmd(token, ValueFactory::create(token.numberDouble)));
00345 
00346         case ETOKEN_STRING:
00347             dstType = Value::V_STRING;
00348             return PCmd(new PushValueCmd(token, ValueFactory::create(token.text)));
00349 
00350         case ETOKEN_ID:
00351             {
00352                 const string &name = token.text;
00353                 if (name == fnc->self.name) {
00354                     // ID resolved as return value of calling function
00355                     if (fnc->self.value.type == Value::V_NULL) {
00356                         std::cerr << Error(E_ERROR, d->vm->fileName, "attempt to read return value in void function", token) << std::endl;
00357                         return PCmd();
00358                     } else {
00359                         dstType = fnc->self.value.type;
00360                         return PCmd(new ReturnCmd(token, true));
00361                     }
00362                 }
00363 
00364                 PVar arg = fnc->args[name];
00365                 if (arg) {
00366                     // ID resolved as argument of calling function
00367                     dstType = arg->value.type;
00368                     arg->used = true;
00369                     return PCmd(new ArgCmd(token, true));
00370                 }
00371 
00372                 PVar lcVar = fnc->vars[name];
00373                 if (lcVar) {
00374                     // ID resolved as local variable of calling function
00375                     dstType = lcVar->value.type;
00376                     lcVar->used = true;
00377                     return PCmd(new LcVarCmd(token, true));
00378                 }
00379 
00380                 PVar glVar = d->vm->glVars[name];
00381                 if (glVar) {
00382                     // ID resolved as global variable
00383                     dstType = glVar->value.type;
00384                     glVar->used = true;
00385                     return PCmd(new GlVarCmd(token, true));
00386                 }
00387 
00388                 // ID not resolved
00389                 std::cerr << Error(E_ERROR, d->vm->fileName, "unknown identifier in expression", token) << std::endl;
00390                 return PCmd();
00391             }
00392         default:
00393             std::cerr << Error(E_ERROR, d->vm->fileName, "unexpected token type in push", token, true) << std::endl;
00394             return PCmd();
00395     }
00396 }
00397 
00398 PCmd CmdFactory::createIf(Token token, PCmd ifCmd, PCmd elseCmd) {
00399     return PCmd(new IfCmd(token, ifCmd, elseCmd));
00400 }
00401 
00402 PCmd CmdFactory::createWhile(Token token, PCmd whileExpr, PCmd whileStat) {
00403     return PCmd(new WhileCmd(token, whileExpr, whileStat));
00404 }
00405 
00406 PCmd CmdFactory::createUnary(Token token) {
00407     switch (token.type) {
00408         case ETOKEN_OP_MINUS:
00409         case ETOKEN_KW_NOT:
00410             return PCmd(new UnaryCmd(token));
00411         default:
00412             std::cerr << Error(E_ERROR, d->vm->fileName, "unexpected token for unary operator", token, true) << std::endl;
00413             return PCmd();
00414     }
00415 }
00416 
00417 PCmd CmdFactory::createBinary(Token token, VType t1, VType t2, VType &dstType) {
00418     switch (token.type) {
00419         case ETOKEN_KW_AND:
00420         case ETOKEN_KW_DIV:
00421         case ETOKEN_KW_EQ:
00422         case ETOKEN_KW_OR:
00423         case ETOKEN_KW_NEQ:
00424         case ETOKEN_OP_GREATER:
00425         case ETOKEN_OP_GREATER_EQ:
00426         case ETOKEN_OP_LESS:
00427         case ETOKEN_OP_LESS_EQ:
00428         case ETOKEN_OP_MINUS:
00429         case ETOKEN_OP_PLUS:
00430         case ETOKEN_OP_SLASH:
00431         case ETOKEN_OP_STAR:
00432             break;
00433         default:
00434             std::cerr << Error(E_ERROR, d->vm->fileName, "unexpected token for binary operator", token, true) << std::endl;
00435             return PCmd();
00436     }
00437     SHARED_PTR(BinaryCmd) cmd(new BinaryCmd(token));
00438 #if 0
00439     std::cerr << "token = " << token << ", t1 = " << t1 << ", t2 = " << t2 << std::endl;
00440 #endif
00441     if (!cmd->chkTypes(t1, t2)) {
00442         // type mismatch on operands
00443         dstType = Value::V_NULL;
00444         return PCmd();
00445     }
00446 
00447     // determine dstType
00448     switch (token.type) {
00449         case ETOKEN_KW_AND:
00450         case ETOKEN_KW_OR:
00451         case ETOKEN_OP_LESS:
00452         case ETOKEN_OP_LESS_EQ:
00453         case ETOKEN_KW_EQ:
00454         case ETOKEN_KW_NEQ:
00455         case ETOKEN_OP_GREATER_EQ:
00456         case ETOKEN_OP_GREATER:
00457             dstType = Value::V_BOOL;
00458             break;
00459 
00460         case ETOKEN_OP_PLUS:
00461             if (t1 == Value::V_STRING) {
00462                 dstType = Value::V_STRING;
00463                 break;
00464             }
00465                                     // go through (!!)
00466         case ETOKEN_OP_MINUS:
00467         case ETOKEN_OP_STAR:
00468             dstType = (t1 == Value::V_INT && t2 == Value::V_INT)
00469                 ? Value::V_INT : Value::V_DOUBLE;
00470             break;
00471 
00472         case ETOKEN_OP_SLASH:
00473             dstType = Value::V_DOUBLE;
00474             break;
00475 
00476         case ETOKEN_KW_DIV:
00477             dstType = Value::V_INT;
00478             break;
00479 
00480         default:
00481             // unexpected token
00482             return PCmd();
00483     }
00484     return cmd;
00485 }
00486 
00487 PCmd CmdFactory::createCall(Token token, unsigned nArgs, bool pushResult) {
00488     return PCmd(new CallCmd(token, nArgs, pushResult));
00489 }
00490 
00491 PCmd CmdFactory::createPrint(Token token, EToken valType, VType &srcType) {
00492     switch (valType) {
00493         case ETOKEN_KW_INT:
00494             srcType = Value::V_INT;
00495             return PCmd(new PrintCmd(token, Value::V_INT));
00496 
00497         case ETOKEN_KW_DOUBLE:
00498             srcType = Value::V_DOUBLE;
00499             return PCmd(new PrintCmd(token, Value::V_DOUBLE));
00500 
00501         case ETOKEN_KW_STRING:
00502             srcType = Value::V_STRING;
00503             return PCmd(new PrintCmd(token, Value::V_STRING));
00504 
00505         default:
00506             std::cerr << Error(E_ERROR, d->vm->fileName, "unexpected type of PrintCmd", token, true) << std::endl;
00507             return PCmd();
00508     }
00509 }
00510 
00511 PCmd CmdFactory::createInput(Token token, Value::VType type, bool pushValue) {
00512     return PCmd(new InputCmd(token, type, pushValue));
00513 }
00514 
00515 // /////////////////////////////////////////////////////////////////////////////
00516 // UnaryCmd implementation
00517 bool UnaryCmd::exec(FncDefinition *fnc) {
00518     Vm *vm = fnc -> vm;
00519 
00520     // pop value from stack
00521     PValue val;
00522     if (!vm->vmStack.pop(val, t_))
00523         return false;
00524 
00525     if (t_.type == ETOKEN_KW_NOT) {
00526         if (val->type != Value::V_BOOL) {
00527             // TODO: mark as internal after tests as this is now handled statically
00528             std::cerr << Error(E_ERROR, vm->fileName, "operand type not allowed for ", t_) << t_ << std::endl;
00529             std::cerr << Error(E_NOTE, vm->fileName, "operand type: ") << val->type << std::endl;
00530             return false;
00531         }
00532         val->boolVal = !(val->boolVal);
00533         return vm->vmStack.push(val, t_);
00534     }
00535 
00536     if (t_.type == ETOKEN_OP_MINUS) {
00537         switch (val->type) {
00538             case Value::V_INT:
00539                 val->intVal = -(val->intVal);
00540                 return vm->vmStack.push(val, t_);
00541             case Value::V_DOUBLE:
00542                 val->doubleVal = -(val->doubleVal);
00543                 return vm->vmStack.push(val, t_);
00544             default:
00545                 // TODO: mark as internal after tests as this is now checked statically
00546                 std::cerr << Error(E_ERROR, vm->fileName, "type not allowed for unary ", t_) << t_ << std::endl;
00547                 std::cerr << Error(E_NOTE, vm->fileName, "expression type: ") << val->type << std::endl;
00548                 return false;
00549         }
00550     }
00551     return false;
00552 }
00553 
00554 // /////////////////////////////////////////////////////////////////////////////
00555 // BinaryCmd implementation
00556 bool BinaryCmd::chkTypes(Value::VType t1, Value::VType t2) {
00557     switch (t_.type) {
00558         // logical operators
00559         case ETOKEN_KW_AND:
00560         case ETOKEN_KW_OR:
00561             return t1 == Value::V_BOOL
00562                 && t2 == Value::V_BOOL;
00563 
00564         // relation operators
00565         case ETOKEN_OP_LESS:
00566         case ETOKEN_OP_LESS_EQ:
00567         case ETOKEN_KW_EQ:
00568         case ETOKEN_KW_NEQ:
00569         case ETOKEN_OP_GREATER_EQ:
00570         case ETOKEN_OP_GREATER:
00571             return t1 == t2 && (t1 == Value::V_INT
00572                     || t1 == Value::V_DOUBLE
00573                     || t2 == Value::V_STRING);
00574 
00575         // arithmetic operators
00576         case ETOKEN_OP_PLUS:
00577             if (t1 == Value::V_STRING && t2 == Value::V_STRING)
00578                 // sting concatenation
00579                 return true;
00580 
00581             // go through (!!)
00582         case ETOKEN_OP_MINUS:
00583         case ETOKEN_OP_STAR:
00584         case ETOKEN_OP_SLASH:
00585             return (t1 == Value::V_INT || t1 == Value::V_DOUBLE)
00586                 && (t2 == Value::V_INT || t2 == Value::V_DOUBLE);
00587 
00588         // extra handling for arithmetic division
00589         case ETOKEN_KW_DIV:
00590             return t1 == Value::V_INT
00591                 && t2 == Value::V_INT;
00592 
00593         default:
00594             // unexpected token
00595             return false;
00596     }
00597 
00598 }
00599 int BinaryCmd::cmp(PConstValue val1, PConstValue val2) {
00600     if (val1->type == Value::V_STRING)
00601         // compare strings
00602         return val1->stringVal.compare(val2->stringVal);
00603 
00604     double d1 = (val1->type == Value::V_DOUBLE)
00605         ? val1->doubleVal : val1->intVal;
00606     double d2 = (val2->type == Value::V_DOUBLE)
00607         ? val2->doubleVal : val2->intVal;
00608     if (d1 < d2)
00609         return -1;
00610     else if (d1 > d2)
00611         return 1;
00612     else
00613         return 0;
00614 }
00615 void BinaryCmd::aluOp(PValue dst, PConstValue src) {
00616     Value::VType tDst = dst->type;
00617     Value::VType tSrc = src->type;
00618     if (tSrc == Value::V_INT && tDst == Value::V_INT)
00619         // int, int --> int
00620         switch (t_.type) {
00621             case ETOKEN_OP_PLUS:    dst->intVal += src->intVal; return;
00622             case ETOKEN_OP_MINUS:   dst->intVal -= src->intVal; return;
00623             case ETOKEN_OP_STAR:    dst->intVal *= src->intVal; return;
00624             default:
00625                                     assert(false);
00626         }
00627 
00628     double dDst = (tDst == Value::V_DOUBLE)
00629         ? dst->doubleVal : dst->intVal;
00630     double dSrc = (tSrc == Value::V_DOUBLE)
00631         ? src->doubleVal : src->intVal;
00632 
00633     dst->type = Value::V_DOUBLE;
00634     switch (t_.type) {
00635         case ETOKEN_OP_PLUS:    dst->doubleVal = dDst + dSrc; break;
00636         case ETOKEN_OP_MINUS:   dst->doubleVal = dDst - dSrc; break;
00637         case ETOKEN_OP_STAR:    dst->doubleVal = dDst * dSrc; break;
00638         default:
00639                                 assert(false);
00640     }
00641 };
00642 bool BinaryCmd::divide(PValue dst, PConstValue src) {
00643     Value::VType tDst = dst->type;
00644     Value::VType tSrc = src->type;
00645     if ((tSrc == Value::V_DOUBLE && 0.0 == src->doubleVal)
00646             || (tSrc == Value::V_INT && 0 == src->intVal))
00647         return false;
00648 
00649     if (t_.type == ETOKEN_KW_DIV) {
00650         dst->intVal /= src->intVal;
00651     } else {
00652         double dDst = (tDst == Value::V_DOUBLE)
00653             ? dst->doubleVal : dst->intVal;
00654         double dSrc = (tSrc == Value::V_DOUBLE)
00655             ? src->doubleVal : src->intVal;
00656         dst->type = Value::V_DOUBLE;
00657         dst->doubleVal = (dDst/dSrc);
00658     }
00659     return true;
00660 }
00661 bool BinaryCmd::exec(FncDefinition *fnc) {
00662     Vm *vm = fnc -> vm;
00663 
00664     // pop values from stack
00665     PValue val1;
00666     PValue val2;
00667     if (!vm->vmStack.pop(val2, t_)
00668             ||!vm->vmStack.pop(val1, t_))
00669         return false;
00670 
00671     // check operand types
00672     if (!chkTypes(val1->type, val2->type)) {
00673         // TODO: mark this as internal after tests as this is now checked statically
00674         std::cerr << Error(E_ERROR, vm->fileName, "type combination is not valid for binary ", t_) << t_ << std::endl;
00675         std::cerr << Error(E_NOTE, vm->fileName, "type of operand 1: ") << val1->type << std::endl;
00676         std::cerr << Error(E_NOTE, vm->fileName, "type of operand 2: ") << val2->type << std::endl;
00677         return false;
00678     }
00679 
00680     switch (t_.type) {
00681         // logical operators
00682         case ETOKEN_KW_AND:         val1->boolVal &= val2->boolVal; break;
00683         case ETOKEN_KW_OR:          val1->boolVal |= val2->boolVal; break;
00684 
00685         // relation operators
00686         case ETOKEN_OP_LESS:        val1 = ValueFactory::create(cmp(val1, val2) <  0); break;
00687         case ETOKEN_OP_LESS_EQ:     val1 = ValueFactory::create(cmp(val1, val2) <= 0); break;
00688         case ETOKEN_KW_EQ:          val1 = ValueFactory::create(cmp(val1, val2) == 0); break;
00689         case ETOKEN_KW_NEQ:         val1 = ValueFactory::create(cmp(val1, val2) != 0); break;
00690         case ETOKEN_OP_GREATER_EQ:  val1 = ValueFactory::create(cmp(val1, val2) >= 0); break;
00691         case ETOKEN_OP_GREATER:     val1 = ValueFactory::create(cmp(val1, val2) >  0); break;
00692 
00693         // arithmetic operators
00694         case ETOKEN_OP_PLUS:
00695             if (val1->type == Value::V_STRING) {
00696                 val1->stringVal += val2->stringVal;
00697                 break;
00698             }
00699 
00700             // go through (!!)
00701         case ETOKEN_OP_MINUS:
00702         case ETOKEN_OP_STAR:
00703             aluOp(val1, val2);
00704             break;
00705 
00706         // extra handling for arithmetic division
00707         case ETOKEN_OP_SLASH:
00708         case ETOKEN_KW_DIV:
00709             if (!divide(val1, val2)) {
00710                 std::cerr << Error(E_ERROR, vm->fileName, "division by zero", t_) << std::endl;
00711                 return false;
00712             }
00713             break;
00714 
00715         default:
00716             // unexpected token
00717             return false;
00718     }
00719 
00720     // push result to stack
00721     return vm->vmStack.push(val1, t_);
00722 }
00723 
00724 // /////////////////////////////////////////////////////////////////////////////
00725 // IfCmd implementation
00726 bool IfCmd::exec(FncDefinition *fnc) {
00727     Vm *vm = fnc->vm;
00728 
00729     // pop value from stack
00730     PValue val;
00731     if (!vm->vmStack.pop(val, t_))
00732         return false;
00733 
00734     // check value type
00735     if (val->type != Value::V_BOOL) {
00736         // TODO: mark this as internal after tests as this is now checked statically
00737         std::cerr << Error(E_ERROR, vm->fileName, "non-bool value given as if condition", t_) << std::endl;
00738         std::cerr << Error(E_NOTE, vm->fileName, "given value: ", t_) << *val << std::endl;
00739         return false;
00740     }
00741 
00742     // call appropriate cmd
00743     return (val -> boolVal)
00744         ? ifCmd_ -> exec(fnc)
00745         : elseCmd_ -> exec(fnc);
00746 }
00747 
00748 // /////////////////////////////////////////////////////////////////////////////
00749 // WhileCmd implementation
00750 bool WhileCmd::exec(FncDefinition *fnc) {
00751     Vm *vm = fnc->vm;
00752 
00753     // while loop implemented as loop :-)
00754     for(;;) {
00755         // evaluate while expression
00756         if (!whileExpr_->exec(fnc))
00757             return false;
00758 
00759         // pop value from stack
00760         PValue val;
00761         if (!vm->vmStack.pop(val, t_))
00762             return false;
00763 
00764         // check value type
00765         if (val->type != Value::V_BOOL) {
00766             // TODO: mark this as internal after tests as this is now checked statically
00767             std::cerr << Error(E_ERROR, vm->fileName, "non-bool value given as while condition", t_) << std::endl;
00768             std::cerr << Error(E_NOTE, vm->fileName, "given value: ", t_) << *val << std::endl;
00769             return false;
00770         }
00771         if (!val->boolVal)
00772             // got false in while condition
00773             return true;
00774 
00775         // call while statement
00776         if (!whileStat_ -> exec(fnc))
00777             return false;
00778     }
00779 }
00780 
00781 // /////////////////////////////////////////////////////////////////////////////
00782 // PrintCmd implementation
00783 bool PrintCmd::exec(FncDefinition *fnc) {
00784     Vm *vm = fnc->vm;
00785     if (!vm->vmStack.popToVar(var_, t_))
00786         return false;
00787 
00788     Value &val = var_.value;
00789     switch (val.type) {
00790         case Value::V_INT:      std::cout << val.intVal     << std::flush; return true;
00791             // FIXME: is the output format same as printf %g ???
00792         case Value::V_DOUBLE:   std::cout << val.doubleVal  << std::flush; return true;
00793         case Value::V_STRING:   std::cout << val.stringVal  << std::flush; return true;
00794         default:
00795             // unhandled type
00796             return false;
00797     }
00798 }
00799 
00800 // /////////////////////////////////////////////////////////////////////////////
00801 // InputCmd implementation
00802 bool InputCmd::exec(FncDefinition *fnc) {
00803     Vm *vm = fnc->vm;
00804     PValue val;
00805     switch (type_) {
00806         case Value::V_INT:
00807             // inputint()
00808             {
00809                 int i;
00810                 std::cin >> i;
00811                 if (!std::cin) {
00812                     std::cerr << Error(E_ERROR, vm->fileName, "failed to read int from stdin", t_) << std::endl;
00813                     return false;
00814                 }
00815                 val = ValueFactory::create(i);
00816                 break;
00817             }
00818         case Value::V_DOUBLE:
00819             // inputdouble()
00820             {
00821                 double d;
00822                 std::cin >> d;
00823                 if (!std::cin) {
00824                     std::cerr << Error(E_ERROR, vm->fileName, "failed to read double from stdin", t_) << std::endl;
00825                     return false;
00826                 }
00827                 val = ValueFactory::create(d);
00828                 break;
00829             }
00830         case Value::V_STRING:
00831             // inputstring()
00832             {
00833                 string s;
00834                 char c;
00835                 bool quoteFound = false;
00836                 for (;;) {
00837                     if (!(std::cin.get(c))) {
00838                         std::cerr << Error(E_ERROR, vm->fileName, "failed to read string from stdin", t_) << std::endl;
00839                         return false;
00840                     }
00841                     if (!quoteFound) {
00842                         if (c == '"')
00843                             quoteFound = true;
00844                     } else {
00845                         if (c == '"')
00846                             break;
00847                         else
00848                             s.push_back(c);
00849                     }
00850                 }
00851                 val = ValueFactory::create(s);
00852                 break;
00853             }
00854         default:
00855             // unhandled type
00856             return false;
00857     }
00858     if (!pushValue_)
00859         return true;
00860     else
00861         return vm->vmStack.push(val, t_);
00862 }
00863 
00864 // /////////////////////////////////////////////////////////////////////////////
00865 // CallCmd implementation
00866 bool CallCmd::exec(FncDefinition *fnc) {
00867     Vm *vm = fnc->vm;
00868     FncDefinition *prototype = vm->fncSet.getDefinition(t_.text);
00869     if (!prototype || prototype->args.size() != nArgs_) {
00870         std::cerr << Error(E_ERROR, vm->fileName, "CALL_CMD failed to match called function", t_, true) << std::endl; 
00871         return false;
00872     }
00873 
00874     // clone for call
00875     SHARED_PTR(FncDefinition) fncCall(new FncDefinition(*prototype));
00876 
00877     // pop fnc arguments
00878     for (unsigned i = 0; i < nArgs_; i++) {
00879         Var &arg = *(fncCall->args[nArgs_-i-1]);
00880         if (!vm->vmStack.popToVar(arg, t_))
00881             return false;
00882     }
00883 
00884     // check call depth
00885     if (vm->callDepth >= vm->maxCallDepth) {
00886         std::cerr << Error(E_ERROR, vm->fileName, "function call depth limit reached", t_) << std::endl;
00887         return false;
00888     }
00889 
00890     // call fnc
00891     vm->callDepth ++;
00892     PCmdList cmdList = fncCall->cmdList;
00893 
00894 #if DEBUG_TRACE_CALL
00895     std::cerr << Color(C_LIGHT_GREEN) << ">>>" << Color(C_NO_COLOR) << " "
00896         << Color(C_YELLOW) << fncCall->self.defined.text << Color(C_NO_COLOR) << ": "
00897         << Color(C_LIGHT_GREEN) << "calling now"
00898         << Color(C_NO_COLOR) << ", call depth: "
00899         << Color(C_LIGHT_BLUE) << vm->callDepth-1 << Color(C_NO_COLOR)
00900         << std::endl;
00901 #endif
00902 
00903     FncDefinition *rawCall = fncCall.operator->();
00904     bool bOk = cmdList->exec(rawCall);
00905 
00906 #if DEBUG_TRACE_CALL
00907     if (bOk)
00908         std::cerr << Color(C_LIGHT_GREEN) << "<<<" << Color(C_NO_COLOR) << " "
00909             << Color(C_YELLOW) << fncCall->self.defined.text << Color(C_NO_COLOR)
00910             << ": " << Color(C_LIGHT_GREEN) << "called ok";
00911     else
00912         std::cerr << Color(C_LIGHT_RED) << "<<<" << Color(C_NO_COLOR) << " "
00913             << Color(C_YELLOW) << fncCall->self.defined.text << Color(C_NO_COLOR)
00914             << ": " << Color(C_LIGHT_RED) << "call failed";
00915     std::cerr << Color(C_NO_COLOR)
00916             << Color(C_NO_COLOR) << ", call depth: "
00917             << Color(C_LIGHT_BLUE) << vm->callDepth-1 << Color(C_NO_COLOR)
00918             << std::endl;
00919 #endif
00920 
00921     vm->callDepth --;
00922     if (!bOk)
00923         return false;
00924 
00925     if (!pushResult_)
00926         return true;
00927     else
00928         return vm->vmStack.pushFromVar(fncCall->self, t_);
00929 }
00930 

Generated on Sat Jul 4 18:32:59 2009 for vyp08 (compiler and interpreter of VYP08 language) by  doxygen 1.5.4