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 "builder.h"
00022
00023 #include "cmd.h"
00024 #include "parser.h"
00025 #include "vm.h"
00026 #include "vypIO.h"
00027
00028 #ifndef BUILDING_DOX
00029 # include <stack>
00030 # include <string>
00031 #endif
00032
00033 using namespace StreamDecorator;
00034 using std::string;
00035
00037 class Builder: public IBuilder {
00038 public:
00039 Builder(Vm *);
00040 virtual ~Builder();
00041 virtual bool hasError() const { return hasError_; }
00042 virtual void errorDetected();
00043 virtual void glVar(EToken type, Token id);
00044 virtual void fncDeclInit(EToken type, Token id);
00045 virtual void fncDeclArg(EToken type);
00046 virtual void fncDecl();
00047 virtual void fncDefInit(EToken type, Token id);
00048 virtual void fncDefArg(EToken type, Token id);
00049 virtual void fncDefVar(EToken type, Token id);
00050 virtual void fncDefBody();
00051 virtual void fncDef();
00052 virtual void assign(Token token);
00053 virtual void ifEnter(Token token);
00054 virtual void ifElse();
00055 virtual void ifLeave();
00056 virtual void whileInit(Token token);
00057 virtual void whileEnter();
00058 virtual void whileLeave();
00059 virtual void pushToken(Token token);
00060 virtual void evalUnOp(Token token);
00061 virtual void evalBinOp(Token token);
00062 virtual void fncCall(Token id, int argsToPop, bool pushResult);
00063 virtual void fncCallPrint(Token id, EToken valType);
00064 private:
00065 Vm *vm_;
00066 bool hasError_;
00067 FncDeclaration *fncDecl_;
00068 FncDefinition *fncDef_;
00069 CmdFactory cmdFactory_;
00070
00071 typedef STD_PAIR(Token, PCmdList) TBlock;
00072 typedef STD_STACK(TBlock) TBlockStack;
00073 TBlockStack blockStack_;
00074
00075 typedef STD_STACK(Value::VType) TTypeStack;
00076 TTypeStack typeStack_;
00077
00078 PVar createVar(EToken type, Token id);
00079 bool appendCmd(PCmd);
00080 bool chkBlockStack();
00081 void pushTypeToStack(Value::VType);
00082 Value::VType popTypeFromStack(const Token &);
00083 void chkTypeOnTop(Value::VType type, const Token &);
00084 };
00085
00086
00087
00088 IBuilder* BuilderFactory::createBuilder(Vm *vm) {
00089 return new Builder(vm);
00090 }
00091
00092
00093
00094 Builder::Builder(Vm *vm):
00095 vm_(vm),
00096 hasError_(false),
00097 fncDecl_(0),
00098 fncDef_(0),
00099 cmdFactory_(vm)
00100 {
00101 }
00102
00103 Builder::~Builder() {
00104 delete fncDecl_;
00105 delete fncDef_;
00106 }
00107
00108 void Builder::errorDetected() {
00109 hasError_ = true;
00110 if (fncDef_ && !blockStack_.empty())
00111 blockStack_.pop();
00112 delete fncDecl_;
00113 delete fncDef_;
00114 fncDecl_ = 0;
00115 fncDef_ = 0;
00116 }
00117
00118 void Builder::glVar(EToken type, Token id) {
00119 PVar var = createVar(type, id);
00120 if (!var)
00121 return;
00122
00123 VarSet &varSet = vm_ -> glVars;
00124 if (!varSet.add(var)) {
00125 hasError_ = true;
00126 std::cerr << Error(E_ERROR, vm_->fileName, "redefinition of global variable", id) << std::endl;
00127 PVar prev = varSet[id.text];
00128 if (prev && prev->defined.lineno)
00129 std::cerr << Error(E_NOTE, vm_->fileName, "previous definition was here", prev->defined.lineno) << std::endl;
00130 }
00131 }
00132
00133 void Builder::fncDeclInit(EToken type, Token id) {
00134 if (fncDecl_) {
00135 std::cerr << Error(E_WARNING, vm_->fileName, "unexpected declaration of function", id, true) << std::endl;
00136 return;
00137 }
00138
00139 PVar var = createVar(type, id);
00140 if (!var)
00141 return;
00142
00143 fncDecl_ = new FncDeclaration;
00144 fncDecl_ -> self = *var;
00145 }
00146
00147 void Builder::fncDeclArg(EToken type) {
00148 if (!fncDecl_)
00149 return;
00150
00151 PVar var = createVar(type, Token());
00152 if (!var)
00153 return;
00154
00155 if (!fncDecl_->args.add(var))
00156 std::cerr << Error(E_WARNING, vm_->fileName, "failed to declare function argument", Token() ,true) << std::endl;
00157 }
00158
00159 void Builder::fncDecl() {
00160 if (!fncDecl_)
00161 return;
00162
00163 FncSet &fncSet = vm_ -> fncSet;
00164 if (!fncSet.addDeclaration(fncDecl_)) {
00165 hasError_ = true;
00166 const string &name = fncDecl_ -> self.name;
00167 std::cerr << Error(E_ERROR, vm_->fileName, "function declaration mismatch", fncDecl_->self.defined) << std::endl;
00168 FncDeclaration *prev = fncSet.getDeclaration(name);
00169 if (prev && prev->self.defined.lineno)
00170 std::cerr << Error(E_NOTE, vm_->fileName, "previous declaration was here", prev->self.defined) << std::endl;
00171 delete fncDecl_;
00172 }
00173
00174 fncDecl_ = 0;
00175 }
00176
00177 void Builder::fncDefInit(EToken type, Token id) {
00178 if (fncDef_) {
00179 std::cerr << Error(E_WARNING, vm_->fileName, "unexpected definition of function", id, true) << std::endl;
00180 return;
00181 }
00182
00183 PVar var = createVar(type, id);
00184 if (!var)
00185 return;
00186
00187 fncDef_ = new FncDefinition(vm_);
00188 fncDef_ -> self = *var;
00189 }
00190
00191 void Builder::fncDefArg(EToken type, Token id) {
00192 if (!fncDef_)
00193 return;
00194
00195 if (id.text == fncDef_->self.name) {
00196 hasError_ = true;
00197 std::cerr << Error(E_ERROR, vm_->fileName, "function argument conflicts with function name", id) << std::endl;
00198 return;
00199 }
00200
00201 PVar var = createVar(type, id);
00202 if (!var)
00203 return;
00204
00205 PVar prev = fncDef_->args[id.text];
00206 if (prev) {
00207 hasError_ = true;
00208 std::cerr << Error(E_ERROR, vm_->fileName, "redefinition of function argument", id) << std::endl;
00209 if (prev->defined.lineno)
00210 std::cerr << Error(E_NOTE, vm_->fileName, "previous definition was here", prev->defined) << std::endl;
00211 return;
00212 }
00213
00214 if (!fncDef_->args.add(var))
00215 std::cerr << Error(E_WARNING, vm_->fileName, "failed to define function argument", Token() ,true) << std::endl;
00216 }
00217
00218 void Builder::fncDefVar(EToken type, Token id) {
00219 if (!fncDef_)
00220 return;
00221
00222 const string &name = id.text;
00223 if (name == fncDef_->self.name) {
00224 hasError_ = true;
00225 std::cerr << Error(E_ERROR, vm_->fileName, "local variable conflicts with function name", id) << std::endl;
00226 return;
00227 }
00228
00229 PVar arg = fncDef_->args[name];
00230 if (arg) {
00231 hasError_ = true;
00232 std::cerr << Error(E_ERROR, vm_->fileName, "local variable conflicts with function parameter", id) << std::endl;
00233 Token &tArg = arg->defined;
00234 if (tArg.lineno)
00235 std::cerr << Error(E_NOTE, vm_->fileName, "argument was defined here", tArg) << std::endl;
00236 return;
00237 }
00238
00239 PVar var = createVar(type, id);
00240 if (!var)
00241 return;
00242
00243 PVar prev = fncDef_->vars[name];
00244 if (prev) {
00245 hasError_ = true;
00246 std::cerr << Error(E_ERROR, vm_->fileName, "redefinition of local variable", id) << std::endl;
00247 if (prev->defined.lineno)
00248 std::cerr << Error(E_NOTE, vm_->fileName, "previous definition was here", prev->defined) << std::endl;
00249 return;
00250 }
00251
00252 if (!fncDef_->vars.add(var))
00253 std::cerr << Error(E_WARNING, vm_->fileName, "failed to define local variable", Token() ,true) << std::endl;
00254 }
00255
00256 void Builder::fncDefBody() {
00257 if (!fncDef_)
00258 return;
00259 const string &name = fncDef_ -> self.name;
00260 FncSet &fncSet = vm_ -> fncSet;
00261
00262 FncDefinition *prev = fncSet.getDefinition(name);
00263 if (prev) {
00264
00265 hasError_ = true;
00266 std::cerr << Error(E_ERROR, vm_->fileName, "redefinition of function", fncDef_->self.defined) << std::endl;
00267 Token &tPrev = prev->self.defined;
00268 if (tPrev.lineno)
00269 std::cerr << Error(E_NOTE, vm_->fileName, "previous definition was here", tPrev) << std::endl;
00270 delete fncDef_;
00271 fncDef_ = 0;
00272 return;
00273 }
00274
00275 if (!fncSet.addDeclaration(new FncDeclaration(*fncDef_))) {
00276
00277 hasError_ = true;
00278 std::cerr << Error(E_ERROR, vm_->fileName, "function declaration/definition mismatch", fncDef_->self.defined) << std::endl;
00279 FncDeclaration *prev = fncSet.getDeclaration(name);
00280 if (prev && prev->self.defined.lineno)
00281 std::cerr << Error(E_NOTE, vm_->fileName, "previous declaration was here", prev->self.defined) << std::endl;
00282 delete fncDef_;
00283 fncDef_ = 0;
00284 return;
00285 }
00286
00287
00288 if (!blockStack_.empty())
00289 std::cerr << Error(E_WARNING, vm_->fileName, "BlockStack offset detected", fncDef_->self.defined, true) << std::endl;
00290 blockStack_.push(TBlock(fncDef_->self.defined, fncDef_->cmdList));
00291 }
00292
00293 void Builder::fncDef() {
00294 if (!fncDef_)
00295 return;
00296
00297 FncSet &fncSet = vm_ -> fncSet;
00298 if (!fncSet.addDefinition(fncDef_)) {
00299 hasError_ = true;
00300 std::cerr << Error(E_ERROR, vm_->fileName, "function definition failed", fncDef_->self.defined, true) << std::endl;
00301 delete fncDef_;
00302 }
00303
00304 if (chkBlockStack()) {
00305 blockStack_.pop();
00306 if (!blockStack_.empty())
00307 std::cerr << Error(E_WARNING, vm_->fileName, "BlockStack offset detected", fncDef_->self.defined, true) << std::endl;
00308 }
00309 fncDef_ = 0;
00310 }
00311
00312 void Builder::assign(Token token) {
00313 if (!fncDef_) {
00314 std::cerr << Error(E_WARNING, vm_->fileName, "assignement not within function definition", token, true) << std::endl;
00315 return;
00316 }
00317 Value::VType dstType;
00318 if (appendCmd (cmdFactory_.createAssign(token, fncDef_, dstType)))
00319 chkTypeOnTop(dstType, token);
00320 }
00321
00322 void Builder::ifEnter(Token token) {
00323 PCmdList ifList(new CmdList);
00324 blockStack_.push(TBlock(token, ifList));
00325 chkTypeOnTop(Value::V_BOOL, token);
00326 }
00327
00328 void Builder::ifElse() {
00329 if (!chkBlockStack())
00330 return;
00331 const TBlock &top = blockStack_.top();
00332
00333 PCmdList elseList(new CmdList);
00334 blockStack_.push(TBlock(top.first, elseList));
00335 }
00336
00337 void Builder::ifLeave() {
00338
00339 if (!chkBlockStack())
00340 return;
00341 TBlock elseBlock = blockStack_.top();
00342 blockStack_.pop();
00343
00344
00345 if (!chkBlockStack())
00346 return;
00347 TBlock ifBlock = blockStack_.top();
00348 blockStack_.pop();
00349
00350
00351 appendCmd(cmdFactory_.createIf(
00352 ifBlock.first,
00353 ifBlock.second,
00354 elseBlock.second));
00355 }
00356
00357 void Builder::whileInit(Token token) {
00358 PCmdList exprList(new CmdList);
00359 blockStack_.push(TBlock(token, exprList));
00360 }
00361
00362 void Builder::whileEnter() {
00363 if (!chkBlockStack())
00364 return;
00365 const TBlock &top = blockStack_.top();
00366
00367 PCmdList statList(new CmdList);
00368 blockStack_.push(TBlock(top.first, statList));
00369 }
00370
00371 void Builder::whileLeave() {
00372
00373 if (!chkBlockStack())
00374 return;
00375 TBlock statBlock = blockStack_.top();
00376 blockStack_.pop();
00377
00378
00379 if (!chkBlockStack())
00380 return;
00381 TBlock exprBlock = blockStack_.top();
00382 blockStack_.pop();
00383
00384
00385 appendCmd(cmdFactory_.createWhile(
00386 exprBlock.first,
00387 exprBlock.second,
00388 statBlock.second));
00389 }
00390
00391 void Builder::pushToken(Token token) {
00392 if (!fncDef_) {
00393 std::cerr << Error(E_WARNING, vm_->fileName, "pushToken not within function definition", token, true) << std::endl;
00394 return;
00395 }
00396 Value::VType dstType;
00397 appendCmd(cmdFactory_.createPush(token, fncDef_, dstType));
00398 pushTypeToStack(dstType);
00399 }
00400
00401 void Builder::evalUnOp(Token token) {
00402 Value::VType vt = popTypeFromStack(token);
00403 if ((token.type == ETOKEN_KW_NOT && vt != Value::V_BOOL)
00404 || (token.type == ETOKEN_OP_MINUS && (vt != Value::V_INT
00405 && vt != Value::V_DOUBLE)))
00406 {
00407 hasError_ = true;
00408 std::cerr << Error(E_ERROR, vm_->fileName, "type not allowed for unary ", token) << token << std::endl;
00409 std::cerr << Error(E_NOTE, vm_->fileName, "expression type: ") << vt << std::endl;
00410 }
00411 appendCmd(cmdFactory_.createUnary(token));
00412 pushTypeToStack(vt);
00413 }
00414
00415 void Builder::evalBinOp(Token token) {
00416 Value::VType t2 = popTypeFromStack(token);
00417 Value::VType t1 = popTypeFromStack(token);
00418 Value::VType dstType;
00419 if (!appendCmd(cmdFactory_.createBinary(token, t1, t2, dstType))
00420 || dstType == Value::V_NULL)
00421 {
00422 hasError_ = true;
00423 std::cerr << Error(E_ERROR, vm_->fileName, "type combination is not valid for binary ", token) << token << std::endl;
00424 std::cerr << Error(E_NOTE, vm_->fileName, "type of operand 1: ") << t1 << std::endl;
00425 std::cerr << Error(E_NOTE, vm_->fileName, "type of operand 2: ") << t2 << std::endl;
00426 }
00427 pushTypeToStack(dstType);
00428 }
00429
00430 void Builder::fncCall(Token id, int argsToPop, bool pushResult) {
00431 const string &name = id.text;
00432 if (name == "print") {
00433 std::cerr << Error(E_ERROR, vm_->fileName, "invalid use of reserved function name", id) << std::endl;
00434 hasError_ = true;
00435 return;
00436 }
00437
00438 FncDeclaration *fnc = vm_->fncSet.getDeclaration(name);
00439 if (!fnc) {
00440 std::cerr << Error(E_ERROR, vm_->fileName, "call of undeclared function", id) << std::endl;
00441 hasError_ = true;
00442 return;
00443 }
00444 unsigned argCnt = fnc->args.size();
00445 if (argCnt != static_cast<unsigned>(argsToPop)) {
00446 std::cerr << Error(E_ERROR, vm_->fileName, "arguments count mismatch in function call", id) << std::endl;
00447 Token &t = fnc->self.defined;
00448 if (t.lineno)
00449 std::cerr << Error(E_NOTE, vm_->fileName, "function is declared here", t) << std::endl;
00450 hasError_ = true;
00451 return;
00452 }
00453 for (unsigned i = 0; i < argCnt; i++) {
00454 unsigned n = argCnt - i - 1;
00455 Value::VType argType = fnc->args[n]->value.type;
00456 chkTypeOnTop(argType, id);
00457 }
00458
00459
00460 bool iInt = name == "inputint";
00461 bool iDouble = name == "inputdouble";
00462 bool iString = name == "inputstring";
00463 if (!pushResult
00464 && (iInt || iDouble || iString))
00465 std::cerr << Error(E_WARNING, vm_->fileName, "return value of input function is not used", id) << std::endl;
00466
00467 if (iInt)
00468 appendCmd(cmdFactory_.createInput(id, Value::V_INT, pushResult));
00469 else if (iDouble)
00470 appendCmd(cmdFactory_.createInput(id, Value::V_DOUBLE, pushResult));
00471 else if (iString)
00472 appendCmd(cmdFactory_.createInput(id, Value::V_STRING, pushResult));
00473 else {
00474
00475 vm_->calleeSet.add(name, id);
00476 appendCmd(cmdFactory_.createCall(id, argsToPop, pushResult));
00477 }
00478 if (pushResult)
00479 pushTypeToStack(fnc->self.value.type);
00480 }
00481
00482 void Builder::fncCallPrint(Token id, EToken valType) {
00483 Value::VType srcType;
00484 if (appendCmd(cmdFactory_.createPrint(id, valType, srcType)))
00485 chkTypeOnTop(srcType, id);
00486 }
00487
00488 PVar Builder::createVar(EToken type, Token id) {
00489 PVar var;
00490 PValue val(new Value);
00491 switch (type) {
00492 case ETOKEN_KW_VOID: val -> type = Value::V_NULL; break;
00493 case ETOKEN_KW_INT: val -> type = Value::V_INT; break;
00494 case ETOKEN_KW_DOUBLE: val -> type = Value::V_DOUBLE; break;
00495 case ETOKEN_KW_STRING: val -> type = Value::V_STRING; break;
00496 default:
00497 std::cerr << Error(E_WARNING, vm_->fileName, "unhandled variable type", id, true) << std::endl;
00498 return var;
00499 }
00500 var.reset(new Var);
00501 var -> name = id.text;
00502 var -> value = *val;
00503 var -> defined = id;
00504 return var;
00505 }
00506
00507 bool Builder::appendCmd(PCmd cmd) {
00508 if (!cmd){
00509 hasError_ = true;
00510 return false;
00511 }
00512 if (!chkBlockStack())
00513 return false;
00514 TBlock &top = blockStack_.top();
00515 PCmdList &list = top.second;
00516 list -> add(cmd);
00517 return true;
00518 }
00519 bool Builder::chkBlockStack() {
00520 if (blockStack_.empty()) {
00521 std::cerr << Error(E_WARNING, vm_->fileName, "BlockStack underflow detected", fncDef_->self.defined, true) << std::endl;
00522 return false;
00523 }
00524 return true;
00525 }
00526 void Builder::pushTypeToStack(Value::VType type) {
00527 #if DEBUG_TRACE_TYPESTACK
00528 std::cerr << Color(C_LIGHT_CYAN) << "TypeStack" << Color(C_NO_COLOR)
00529 << " <-- " << type << std::endl;
00530 #endif
00531 typeStack_.push(type);
00532 }
00533 Value::VType Builder::popTypeFromStack(const Token &t) {
00534 Value::VType type = Value::V_NULL;
00535 if (typeStack_.empty()) {
00536 std::cerr << Error(E_WARNING, vm_->fileName, "TypeStack underflow detected", t, true) << std::endl;
00537 } else {
00538 type = typeStack_.top();
00539 typeStack_.pop();
00540 #if DEBUG_TRACE_TYPESTACK
00541 std::cerr << Color(C_LIGHT_CYAN) << "TypeStack" << Color(C_NO_COLOR)
00542 << " --> " << type << std::endl;
00543 #endif
00544 }
00545 return type;
00546 }
00547 void Builder::chkTypeOnTop(Value::VType dstType, const Token &t) {
00548 Value::VType srcType = popTypeFromStack(t);
00549 if (srcType != dstType) {
00550 hasError_ = true;
00551 std::cerr << Error(E_ERROR, vm_->fileName, "type mismatch", t) << std::endl;
00552 std::cerr << Error(E_NOTE, vm_->fileName, " expression type: ") << srcType << std::endl;
00553 std::cerr << Error(E_NOTE, vm_->fileName, "destination type: ") << dstType << std::endl;
00554 }
00555 }
00556
00557
00558
00559 struct FncFactory::Private {
00560 Vm *const vm;
00561 Private(Vm *vm_):
00562 vm(vm_)
00563 {
00564 }
00565 static bool addDefinition(Vm *, FncDefinition *);
00566 static FncDefinition* createFnc(Vm *, string, PValue);
00567 };
00568 FncFactory::FncFactory(Vm *vm):
00569 d(new Private(vm))
00570 {
00571 }
00572 FncFactory::~FncFactory() {
00573 delete d;
00574 }
00575 bool FncFactory::initVm(Vm *vm) {
00576 FncFactory *factory = new FncFactory(vm);
00577
00578
00579 vm->calleeSet.add("main", Token());
00580 FncDeclaration *declMain = factory -> createMainDecl();
00581 bool bOk = declMain;
00582 bOk &= vm->fncSet.addDeclaration(declMain);
00583
00584
00585 bOk &= Private::addDefinition (vm, factory -> createPrint());
00586 bOk &= Private::addDefinition (vm, factory -> createInputString());
00587 bOk &= Private::addDefinition (vm, factory -> createInputInt());
00588 bOk &= Private::addDefinition (vm, factory -> createInputDouble());
00589
00590 delete factory;
00591 return bOk;
00592 }
00593 bool FncFactory::Private::addDefinition(Vm *vm, FncDefinition *fnc) {
00594 if (!vm || !fnc)
00595 return false;
00596
00597 if (!vm->fncSet.addDefinition(fnc))
00598 return false;
00599
00600 vm->calleeSet.add(fnc->self.name, Token());
00601 return true;
00602 }
00603
00604 FncDefinition* FncFactory::Private::createFnc(Vm *vm, string name, PValue val) {
00605 PVar var(new Var);
00606 var -> name = name;
00607 var -> value = *val;
00608
00609 FncDefinition *fnc = new FncDefinition(vm);
00610 fnc -> self = *var;
00611 return fnc;
00612 }
00613
00614 FncDeclaration* FncFactory::createMainDecl() {
00615 PVar var(new Var);
00616 var -> name = "main";
00617 var -> value = *(ValueFactory::create());
00618
00619 FncDeclaration *mainDecl = new FncDeclaration;
00620 mainDecl -> self = *var;
00621 return mainDecl;
00622 }
00623
00624 FncDefinition* FncFactory::createPrint() {
00625 return Private::createFnc(d->vm, "print",
00626 ValueFactory::create(false));
00627 }
00628
00629 FncDefinition* FncFactory::createInputString() {
00630 return Private::createFnc(d->vm, "inputstring",
00631 ValueFactory::create(string()));
00632 }
00633
00634 FncDefinition* FncFactory::createInputInt() {
00635 return Private::createFnc(d->vm, "inputint",
00636 ValueFactory::create(0));
00637 }
00638
00639 FncDefinition* FncFactory::createInputDouble() {
00640 return Private::createFnc(d->vm, "inputdouble",
00641 ValueFactory::create(0.0));
00642 }
00643