00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
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
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
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
00313 dstType = arg->value.type;
00314 return PCmd(new ArgCmd(token, false));
00315 }
00316
00317 PVar lcVar = fnc->vars[name];
00318 if (lcVar) {
00319
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
00327 dstType = glVar->value.type;
00328 return PCmd(new GlVarCmd(token, false));
00329 }
00330
00331
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
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
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
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
00383 dstType = glVar->value.type;
00384 glVar->used = true;
00385 return PCmd(new GlVarCmd(token, true));
00386 }
00387
00388
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
00443 dstType = Value::V_NULL;
00444 return PCmd();
00445 }
00446
00447
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
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
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
00517 bool UnaryCmd::exec(FncDefinition *fnc) {
00518 Vm *vm = fnc -> vm;
00519
00520
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
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
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
00556 bool BinaryCmd::chkTypes(Value::VType t1, Value::VType t2) {
00557 switch (t_.type) {
00558
00559 case ETOKEN_KW_AND:
00560 case ETOKEN_KW_OR:
00561 return t1 == Value::V_BOOL
00562 && t2 == Value::V_BOOL;
00563
00564
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
00576 case ETOKEN_OP_PLUS:
00577 if (t1 == Value::V_STRING && t2 == Value::V_STRING)
00578
00579 return true;
00580
00581
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
00589 case ETOKEN_KW_DIV:
00590 return t1 == Value::V_INT
00591 && t2 == Value::V_INT;
00592
00593 default:
00594
00595 return false;
00596 }
00597
00598 }
00599 int BinaryCmd::cmp(PConstValue val1, PConstValue val2) {
00600 if (val1->type == Value::V_STRING)
00601
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
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
00665 PValue val1;
00666 PValue val2;
00667 if (!vm->vmStack.pop(val2, t_)
00668 ||!vm->vmStack.pop(val1, t_))
00669 return false;
00670
00671
00672 if (!chkTypes(val1->type, val2->type)) {
00673
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
00682 case ETOKEN_KW_AND: val1->boolVal &= val2->boolVal; break;
00683 case ETOKEN_KW_OR: val1->boolVal |= val2->boolVal; break;
00684
00685
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
00694 case ETOKEN_OP_PLUS:
00695 if (val1->type == Value::V_STRING) {
00696 val1->stringVal += val2->stringVal;
00697 break;
00698 }
00699
00700
00701 case ETOKEN_OP_MINUS:
00702 case ETOKEN_OP_STAR:
00703 aluOp(val1, val2);
00704 break;
00705
00706
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
00717 return false;
00718 }
00719
00720
00721 return vm->vmStack.push(val1, t_);
00722 }
00723
00724
00725
00726 bool IfCmd::exec(FncDefinition *fnc) {
00727 Vm *vm = fnc->vm;
00728
00729
00730 PValue val;
00731 if (!vm->vmStack.pop(val, t_))
00732 return false;
00733
00734
00735 if (val->type != Value::V_BOOL) {
00736
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
00743 return (val -> boolVal)
00744 ? ifCmd_ -> exec(fnc)
00745 : elseCmd_ -> exec(fnc);
00746 }
00747
00748
00749
00750 bool WhileCmd::exec(FncDefinition *fnc) {
00751 Vm *vm = fnc->vm;
00752
00753
00754 for(;;) {
00755
00756 if (!whileExpr_->exec(fnc))
00757 return false;
00758
00759
00760 PValue val;
00761 if (!vm->vmStack.pop(val, t_))
00762 return false;
00763
00764
00765 if (val->type != Value::V_BOOL) {
00766
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
00773 return true;
00774
00775
00776 if (!whileStat_ -> exec(fnc))
00777 return false;
00778 }
00779 }
00780
00781
00782
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
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
00796 return false;
00797 }
00798 }
00799
00800
00801
00802 bool InputCmd::exec(FncDefinition *fnc) {
00803 Vm *vm = fnc->vm;
00804 PValue val;
00805 switch (type_) {
00806 case Value::V_INT:
00807
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
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
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
00856 return false;
00857 }
00858 if (!pushValue_)
00859 return true;
00860 else
00861 return vm->vmStack.push(val, t_);
00862 }
00863
00864
00865
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
00875 SHARED_PTR(FncDefinition) fncCall(new FncDefinition(*prototype));
00876
00877
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
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
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