add some hacky code to allow passing sfc files with -b
[openc2e.git] / caosScript.cpp
blob42f514defb6b695c8b4d5304d7845d173f9d0e12
1 /*
2 * caosScript.cpp
3 * openc2e
5 * Created by Alyssa Milburn on Wed May 26 2004.
6 * Copyright (c) 2004 Alyssa Milburn. All rights reserved.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
20 #include "bytecode.h"
21 #include "cmddata.h"
22 #include "exceptions.h"
23 #include "caosScript.h"
24 #include "caoslexer.h"
25 #include "caosVM.h"
26 #include "openc2e.h"
27 #include "Engine.h"
28 #include "World.h"
29 #include "token.h"
30 #include "dialect.h"
31 #include "util.h"
32 #include <iostream>
33 #include <sstream>
34 #include <algorithm>
35 #include <cstring>
36 #include <boost/format.hpp>
37 #include <boost/scoped_ptr.hpp>
39 using std::string;
41 class unexpectedEOIexception { };
43 script::~script() {
46 // resolve relocations into fixed addresses
47 void script::link() {
48 ops.push_back(caosOp(CAOS_STOP, 0, -1));
49 assert(!linked);
50 // std::cout << "Pre-link:" << std::endl << dump();
51 // check relocations
52 for (unsigned int i = 1; i < relocations.size(); i++) {
53 // handle relocations-to-relocations
54 int p = relocations[i];
55 while (p < 0)
56 p = relocations[-p];
57 relocations[i] = p;
59 for (unsigned int i = 0; i < ops.size(); i++) {
60 if (op_is_relocatable(ops[i].opcode) && ops[i].argument < 0)
61 ops[i].argument = relocations[-ops[i].argument];
63 linked = true;
64 // std::cout << "Post-link:" << std::endl << dump();
65 relocations.clear();
68 script::script(const Dialect *v, const std::string &fn)
69 : fmly(-1), gnus(-1), spcs(-1), scrp(-1),
70 dialect(v), filename(fn)
72 // advance past reserved index 0
73 ops.push_back(caosOp(CAOS_NOP, 0, -1));
74 relocations.push_back(0);
75 linked = false;
78 script::script(const Dialect *v, const std::string &fn,
79 int fmly_, int gnus_, int spcs_, int scrp_)
80 : fmly(fmly_), gnus(gnus_), spcs(spcs_), scrp(scrp_),
81 dialect(v), filename(fn)
83 ops.push_back(caosOp(CAOS_NOP, 0, -1));
84 relocations.push_back(0);
85 linked = false;
88 std::string script::dump() {
89 std::ostringstream oss;
90 oss << "Relocations:" << std::endl;
91 for (unsigned int i = 1; i < relocations.size(); i++) {
92 oss << boost::format("%08d -> %08d") % i % relocations[i]
93 << std::endl;
95 oss << "Code:" << std::endl;
96 for (unsigned int i = 0; i < ops.size(); i++) {
97 oss << boost::format("%08d: ") % i;
98 oss << dumpOp(dialect, ops[i]);
99 oss << std::endl;
101 return oss.str();
104 caosScript::caosScript(const std::string &dialect, const std::string &fn) {
105 enumdepth = 0;
106 d = dialects[dialect].get();
107 if (!d)
108 throw parseException(std::string("Unknown dialect ") + dialect);
109 current = installer = shared_ptr<script> (new script(d, fn));
110 filename = fn;
113 caosScript::~caosScript() {
114 // Nothing to do, yay shared_ptr!
117 void caosScript::installScripts() {
118 std::vector<shared_ptr<script> >::iterator i = scripts.begin();
119 while (i != scripts.end()) {
120 shared_ptr<script> s = *i;
121 world.scriptorium.addScript(s->fmly, s->gnus, s->spcs, s->scrp, s);
122 i++;
126 void caosScript::installInstallScript(unsigned char family, unsigned char genus, unsigned short species, unsigned short eventid) {
127 assert((d->name == "c1") || (d->name == "c2"));
129 installer->fmly = family;
130 installer->gnus = genus;
131 installer->spcs = species;
132 installer->scrp = eventid;
134 world.scriptorium.addScript(installer->fmly, installer->gnus, installer->spcs, installer->scrp, installer);
138 saveVisit::saveVisit(caosScript *s)
139 : scr(s)
142 void saveVisit::operator()(const CAOSCmd &cmd) const {
143 scr->errindex = scr->traceindex = cmd.traceidx - 1;
144 if (cmd.op->rettype != CI_VARIABLE) {
145 throw parseException(std::string("RValue ") + cmd.op->fullname + " used where LValue expected");
147 scr->emitOp(CAOS_RESTORE_AUX, cmd.arguments.size());
148 scr->emitOp(CAOS_SAVE_CMD, scr->d->cmd_index(cmd.op));
151 evalVisit::evalVisit(caosScript *s, bool save_here_)
152 : scr(s), save_here(save_here_)
157 void evalVisit::operator()(const CAOSCmd &cmd) const {
158 for (size_t i = 0; i < cmd.arguments.size(); i++) {
159 bool save_there = (cmd.op->argtypes[i] == CI_VARIABLE);
160 cmd.arguments[i]->eval(scr, save_there);
162 scr->traceindex = cmd.traceidx - 1;
163 // If we're to be invoked to save our result later,
164 // stash our args for that time.
165 if (save_here) {
166 // Note: These indices refer to stack positions, with 0 being the top.
167 // We thus transfer the arguments in reverse order, as the order will again be
168 // reversed when the stack is restored.
169 for (size_t i = 0; i < cmd.arguments.size(); i++)
170 scr->emitOp(CAOS_PUSH_AUX, i);
172 scr->emitOp(CAOS_CMD, scr->d->cmd_index(cmd.op));
173 // If we emit variable-result arguments as well, we need to move our
174 // result down below them.
175 // This is theoretical at the moment - no expression-type commands also
176 // write back to their args.
178 if (cmd.op->rettype != CI_COMMAND) {
179 int rotcount = 0;
180 for (size_t i = 0; cmd.op->argtypes[i] != CI_END; i++) {
181 if (cmd.op->argtypes[i] == CI_VARIABLE)
182 rotcount++;
184 if (rotcount)
185 scr->emitOp(CAOS_STACK_ROT, rotcount);
187 for (int i = cmd.arguments.size() - 1; i >= 0; i--) {
188 if (cmd.op->argtypes[i] == CI_VARIABLE)
189 cmd.arguments[i]->save(scr);
193 void evalVisit::operator()(const caosVar &v) const {
194 if (v.hasInt()) {
195 int val = v.getInt();
196 if (val >= -(1 << 24) && val < (1 << 24)) {
197 scr->emitOp(CAOS_CONSTINT, val);
198 return;
201 scr->current->consts.push_back(v);
202 scr->emitOp(CAOS_CONST, scr->current->consts.size() - 1);
204 void evalVisit::operator()(const bytestring_t &bs) const {
205 scr->current->bytestrs.push_back(bs);
206 scr->emitOp(CAOS_BYTESTR, scr->current->bytestrs.size() - 1);
209 int costVisit::operator()(const CAOSCmd &cmd) const {
210 int accum = cmd.op->evalcost;
211 for (size_t i = 0; i < cmd.arguments.size(); i++)
212 accum += cmd.arguments[i]->cost();
213 return accum;
216 // parser states
217 enum {
218 ST_INSTALLER,
219 ST_BODY,
220 ST_REMOVAL,
221 ST_DOIF,
222 ST_ENUM,
223 ST_LOOP,
224 ST_REPS,
225 ST_INVALID
228 struct doifinfo {
229 int failreloc;
230 int donereloc;
233 struct repsinfo {
234 int jnzreloc;
235 int loopidx;
239 token *caosScript::tokenPeek() {
240 if ((size_t)curindex >= tokens->size())
241 return NULL;
242 return &(*tokens)[curindex];
245 token *caosScript::getToken(toktype expected) {
246 token *t = tokenPeek();
247 token dummy;
248 token &r = (t ? *t : dummy);
250 errindex = curindex;
252 if (expected != ANYTOKEN && r.type() != expected)
253 r.unexpected();
255 curindex++;
257 return t;
260 void caosScript::putBackToken(token *) {
261 curindex--;
262 errindex = curindex - 1; // curindex refers to the /next/ token to be parsed
263 // so make sure we refer to the token before it
266 void caosScript::parse(std::istream &in) {
267 assert(!tokens);
268 // slurp our input stream
269 std::string caostext = readfile(in);
270 // run the token parser
272 bool using_c2;
273 using_c2 = (d->name == "c1" || d->name == "c2");
275 tokens = shared_ptr<std::vector<token> >(new std::vector<token>());
276 lexcaos(*tokens, caostext.c_str(), using_c2);
278 curindex = errindex = traceindex = 0;
280 try {
281 parseloop(ST_INSTALLER, NULL);
283 std::ostringstream oss;
284 shared_ptr<std::vector<toktrace> > tokinfo(new std::vector<toktrace>());
285 for (size_t p = 0; p < tokens->size(); p++) {
286 std::string tok = (*tokens)[p].format();
287 int len = tok.size();
288 if (len > 65535) {
289 errindex = p;
290 throw parseException("Overlong token");
292 oss << tok << " ";
293 tokinfo->push_back(toktrace(len, (*tokens)[p].lineno));
295 shared_str code(oss.str());
296 installer->code = code;
297 installer->tokinfo = tokinfo;
298 installer->link();
299 if (removal) {
300 removal->link();
301 removal->tokinfo = tokinfo;
302 removal->code = code;
304 std::vector<shared_ptr<script> >::iterator i = scripts.begin();
305 while (i != scripts.end()) {
306 (*i)->tokinfo = tokinfo;
307 (*i)->code = code;
308 (*i++)->link();
310 } catch (parseException &e) {
311 e.filename = filename;
312 if (!tokens)
313 throw;
314 if (errindex < 0 || (size_t)errindex >= tokens->size())
315 throw;
316 e.lineno = (*tokens)[errindex].lineno;
317 e.context = boost::shared_ptr<std::vector<token> >(new std::vector<token>());
318 /* We'd like to capture N tokens on each side of the target, but
319 * if we can't get all those from one side, get it from the other.
321 int contextlen = 5;
322 int leftct = contextlen;
323 int rightct = contextlen;
325 if (errindex < leftct) {
326 rightct += leftct - errindex;
327 leftct = errindex;
329 if ((size_t)(errindex + rightct + 1) >= tokens->size()) {
330 int overflow = errindex + rightct + 1 - tokens->size();
331 rightct -= overflow;
332 while (overflow > 0 && errindex > leftct) {
333 overflow--;
334 leftct++;
337 assert(leftct >= 0 && rightct >= 0 && errindex >= leftct && (size_t)(errindex + rightct) < tokens->size());
339 if (errindex - leftct != 0) {
340 e.context->push_back(token());
341 e.context->back().payload = std::string("...");
344 for (int i = errindex - leftct; i < errindex + rightct; i++) {
345 e.context->push_back((*tokens)[i]);
347 if (errindex + rightct + 1 < (int)tokens->size()) {
348 e.context->push_back(token());
349 e.context->back().payload = std::string("...");
351 e.ctxoffset = leftct;
352 throw;
356 const cmdinfo *caosScript::readCommand(token *t, const std::string &prefix) {
357 std::string fullname = prefix + t->word();
358 errindex = t->index + 1;
359 const cmdinfo *ci = d->find_command(fullname.c_str());
360 // See if there'{s a subcommand namespace
361 token *t2 = NULL;
362 try {
363 t2 = getToken(TOK_WORD);
364 if (!t2 || t2->type() != TOK_WORD)
365 throw parseException("dummy");
366 return readCommand(t2, fullname + " ");
367 } catch (parseException &e) {
368 if (ci->argtypes && ci->argtypes[0] == CI_SUBCOMMAND)
369 throw;
370 if (t2)
371 putBackToken(t2);
372 return ci;
376 void caosScript::emitOp(opcode_t op, int argument) {
377 if (op == CAOS_YIELD && engine.version < 3 && enumdepth > 0)
378 return;
379 current->ops.push_back(caosOp(op, argument, traceindex));
382 void caosScript::emitExpr(boost::shared_ptr<CAOSExpression> ce) {
383 ce->eval(this, false);
384 int cost = ce->cost();
385 if (cost)
386 emitOp(CAOS_YIELD, cost);
389 boost::shared_ptr<CAOSExpression> caosScript::readExpr(const enum ci_type xtype) {
390 token *t = getToken();
391 traceindex = errindex = curindex;
392 if (xtype == CI_BAREWORD) {
393 if (t->type() == TOK_WORD) {
394 return boost::shared_ptr<CAOSExpression>(new CAOSExpression(errindex, caosVar(t->word())));
395 } else if (t->type() == TOK_CONST) {
396 if (t->constval().getType() != CAOSSTR)
397 t->unexpected();
398 return boost::shared_ptr<CAOSExpression>(new CAOSExpression(errindex, t->constval()));
399 } else {
400 t->unexpected();
402 assert(!"UNREACHABLE");
403 return boost::shared_ptr<CAOSExpression>();
405 switch (t->type()) {
406 case TOK_CONST:
407 return boost::shared_ptr<CAOSExpression>(new CAOSExpression(errindex, t->constval()));
408 case TOK_BYTESTR:
409 return boost::shared_ptr<CAOSExpression>(new CAOSExpression(errindex, t->bytestr()));
410 case TOK_WORD: break; // fall through to remainder of function
411 default: t->unexpected();
414 std::string oldpayload = t->word();
415 if (t->word() == "face" && xtype != CI_COMMAND) {
416 // horrible hack, yay
417 if (xtype == CI_NUMERIC)
418 t->payload = std::string("face int");
419 else
420 t->payload = std::string("face string");
423 boost::shared_ptr<CAOSExpression> ce(new CAOSExpression(errindex, CAOSCmd()));
424 CAOSCmd *cmd = boost::get<CAOSCmd>(&ce->value);
426 if (t->word().size() == 4 && isdigit(t->word()[2]) && isdigit(t->word()[3])) {
427 if ( !strncmp(t->word().c_str(), "va", 2)
428 || !strncmp(t->word().c_str(), "ov", 2)
429 || !strncmp(t->word().c_str(), "mv", 2)) {
430 int idx = atoi(t->word().c_str() + 2);
431 t->payload = t->word().substr(0, 2) + "xx";
432 const cmdinfo *op = readCommand(t, std::string("expr "));
433 t->payload = oldpayload;
435 boost::shared_ptr<CAOSExpression> arg(new CAOSExpression(errindex, caosVar(idx)));
436 cmd->op = op;
437 cmd->arguments.push_back(arg);
438 return ce;
442 if (t->word().size() == 4 && isdigit(t->word()[3]) && engine.version < 3) {
443 // OBVx VARx hacks
444 if ( !strncmp(t->word().c_str(), "obv", 3)
445 || !strncmp(t->word().c_str(), "var", 3)) {
446 int idx = atoi(t->word().c_str() + 3);
447 t->payload = t->word().substr(0, 3) + "x";
448 const cmdinfo *op = readCommand(t, std::string("expr "));
449 t->payload = oldpayload;
451 boost::shared_ptr<CAOSExpression> arg(new CAOSExpression(errindex, caosVar(idx)));
452 cmd->op = op;
453 cmd->arguments.push_back(arg);
454 return ce;
458 const cmdinfo *ci = readCommand(t, std::string(xtype == CI_COMMAND ? "cmd " : "expr "));
459 t->payload = oldpayload;
460 cmd->op = ci;
461 for (int i = 0; ci->argtypes[i] != CI_END; i++) {
462 cmd->arguments.push_back(readExpr(ci->argtypes[i]));
464 return ce;
467 int caosScript::readCond() {
468 token *t = getToken(TOK_WORD);
469 typedef struct { const char *n; int cnd; } cond_entry;
470 const static cond_entry conds[] = {
471 { "eq", CEQ },
472 { "gt", CGT },
473 { "ge", CGE },
474 { "lt", CLT },
475 { "le", CLE },
476 { "ne", CNE },
477 { "bt", CBT },
478 { "bf", CBF },
479 { NULL, 0 }
482 const cond_entry *c = conds;
483 while (c->n != NULL) {
484 if (t->word() == c->n)
485 return c->cnd;
486 c++;
488 throw parseException(std::string("Unexpected non-condition word: ") + t->word());
491 void caosScript::parseCondition() {
492 emitOp(CAOS_CONSTINT, 1);
494 bool nextIsAnd = true;
495 while (1) {
496 boost::shared_ptr<CAOSExpression> a1, a2;
497 a1 = readExpr(CI_ANYVALUE);
498 int cond = readCond();
499 a2 = readExpr(CI_ANYVALUE);
500 emitExpr(a1);
501 emitExpr(a2);
502 emitOp(CAOS_COND, cond | (nextIsAnd ? CAND : COR));
504 token *peek = tokenPeek();
505 if (!peek) break;
506 if (peek->type() != TOK_WORD) break;
507 if (peek->word() == "and") {
508 getToken();
509 nextIsAnd = true;
510 } else if (peek->word() == "or") {
511 getToken();
512 nextIsAnd = false;
513 } else break;
517 void caosScript::parseloop(int state, void *info) {
518 token *t;
519 while ((t = getToken(ANYTOKEN))) {
520 traceindex = errindex;
521 if (t->type() == EOI) {
522 switch (state) {
523 case ST_INSTALLER:
524 case ST_BODY:
525 case ST_REMOVAL:
526 return;
527 default:
528 throw parseException("Unexpected end of input");
531 if (t->type() != TOK_WORD) {
532 throw parseException("Unexpected non-word token");
534 if (t->word() == "scrp") {
535 if (state != ST_INSTALLER && state != ST_BODY && state != ST_REMOVAL)
536 throw parseException("Unexpected SCRP");
537 assert(!enumdepth);
538 state = ST_BODY;
539 int bits[4];
540 for (int i = 0; i < 4; i++) {
541 caosVar val = getToken(TOK_CONST)->constval();
542 if (!val.getType() == CAOSINT)
543 throw parseException("Expected integer constant");
544 bits[i] = val.getInt();
546 int fmly = bits[0];
547 int gnus = bits[1];
548 int spcs = bits[2];
549 int scrp = bits[3];
550 scripts.push_back(shared_ptr<script>(new script(d, filename, fmly, gnus, spcs, scrp)));
551 current = scripts.back();
552 } else if (t->word() == "rscr") {
553 if (state == ST_INSTALLER || state == ST_BODY || state == ST_REMOVAL)
554 state = ST_REMOVAL;
555 else
556 throw parseException("Unexpected RSCR");
557 if (!removal)
558 removal = shared_ptr<script>(new script(d, filename));
559 current = removal;
560 } else if (t->word() == "iscr") {
561 if (state == ST_INSTALLER || state == ST_BODY || state == ST_REMOVAL)
562 state = ST_INSTALLER;
563 else
564 throw parseException("Unexpected RSCR");
565 assert(!enumdepth);
566 current = installer;
567 } else if (t->word() == "endm") {
568 emitOp(CAOS_STOP, 0);
570 if (state == ST_INSTALLER || state == ST_BODY || state == ST_REMOVAL) {
571 assert(!enumdepth);
572 state = ST_INSTALLER;
573 current = installer;
574 } else {
575 // I hate you. Die in a fire.
576 putBackToken(t);
577 return;
579 // No we will not emit c_ENDM() thankyouverymuch
581 } else if (t->word() == "enum"
582 || t->word() == "esee"
583 || t->word() == "etch"
584 || t->word() == "epas"
585 || t->word() == "econ") {
586 int nextreloc = current->newRelocation();
587 putBackToken(t);
589 enumdepth++;
590 emitExpr(readExpr(CI_COMMAND));
591 emitOp(CAOS_JMP, nextreloc);
592 int startp = current->getNextIndex();
593 parseloop(ST_ENUM, NULL);
594 enumdepth--;
595 current->fixRelocation(nextreloc);
597 emitCmd("cmd next");
598 emitOp(CAOS_ENUMPOP, startp);
599 } else if (t->word() == "next") {
600 if (state != ST_ENUM) {
601 throw parseException("Unexpected NEXT");
603 return;
605 } else if (t->word() == "subr") {
606 // Yes, this will work in a doif or whatever. This is UB, it may
607 // be made to not compile later.
608 t = getToken(TOK_WORD);
609 std::string label = t->word();
610 emitOp(CAOS_STOP, 0);
611 current->affixLabel(label);
612 } else if (t->word() == "gsub") {
613 t = getToken(TOK_WORD);
614 std::string label = t->word();
615 emitOp(CAOS_GSUB, current->getLabel(label));
617 } else if (t->word() == "loop") {
618 int loop = current->getNextIndex();
619 emitCmd("cmd loop");
620 parseloop(ST_LOOP, (void *)&loop);
621 } else if (t->word() == "untl") {
622 if (state != ST_LOOP)
623 throw parseException("Unexpected UNTL");
624 // TODO: zerocost logic inversion - do in c_UNTL()?
625 int loop = *(int *)info;
626 int out = current->newRelocation();
627 parseCondition();
628 emitCmd("cmd untl");
629 emitOp(CAOS_CJMP, out);
630 emitOp(CAOS_JMP, loop);
631 current->fixRelocation(out);
632 return;
633 } else if (t->word() == "ever") {
634 if (state != ST_LOOP)
635 throw parseException("Unexpected EVER");
636 int loop = *(int *)info;
637 emitOp(CAOS_JMP, loop);
638 return;
640 } else if (t->word() == "reps") {
641 struct repsinfo ri;
642 ri.jnzreloc = current->newRelocation();
643 putBackToken(t);
644 emitExpr(readExpr(CI_COMMAND));
645 emitOp(CAOS_JMP, ri.jnzreloc);
646 ri.loopidx = current->getNextIndex();
647 parseloop(ST_REPS, (void *)&ri);
648 } else if (t->word() == "repe") {
649 if (state != ST_REPS)
650 throw parseException("Unexpected repe");
651 struct repsinfo *ri = (repsinfo *)info;
652 current->fixRelocation(ri->jnzreloc);
653 emitOp(CAOS_DECJNZ, ri->loopidx);
654 emitCmd("cmd repe");
655 return;
657 } else if (t->word() == "doif") {
658 struct doifinfo di;
659 di.donereloc = current->newRelocation();
660 di.failreloc = current->newRelocation();
661 int okreloc = current->newRelocation();
663 parseCondition();
664 emitCmd("cmd doif");
665 emitOp(CAOS_CJMP, okreloc);
666 emitOp(CAOS_JMP, di.failreloc);
667 current->fixRelocation(okreloc);
668 parseloop(ST_DOIF, (void *)&di);
669 if (di.failreloc)
670 current->fixRelocation(di.failreloc);
671 current->fixRelocation(di.donereloc);
672 emitCmd("cmd endi");
673 } else if (t->word() == "elif") {
674 if (state != ST_DOIF) {
675 // XXX this is horrible
676 t->payload = std::string("doif");
677 continue;
679 struct doifinfo *di = (struct doifinfo *)info;
680 int okreloc = current->newRelocation();
682 emitOp(CAOS_JMP, di->donereloc);
683 current->fixRelocation(di->failreloc);
684 di->failreloc = current->newRelocation();
685 parseCondition();
686 emitCmd("cmd elif");
687 emitOp(CAOS_CJMP, okreloc);
688 emitOp(CAOS_JMP, di->failreloc);
689 current->fixRelocation(okreloc);
690 parseloop(ST_DOIF, info);
691 return;
692 } else if (t->word() == "else") {
693 if (state != ST_DOIF)
694 throw parseException("Unexpected ELSE");
695 struct doifinfo *di = (struct doifinfo *)info;
696 if (!di->failreloc)
697 throw parseException("Duplicate ELSE");
698 emitOp(CAOS_JMP, di->donereloc);
699 current->fixRelocation(di->failreloc);
700 di->failreloc = 0;
701 emitCmd("cmd else");
702 } else if (t->word() == "endi") {
703 if (state != ST_DOIF) {
704 if (engine.version >= 3)
705 throw parseException("Unexpected ENDI");
706 // you are a horrible person if you get here
707 // damn you CL coders.
708 continue;
710 return;
711 } else {
712 if (t->word() == "dbg:") {
713 token *t2 = tokenPeek();
714 if (t2 && t2->type() == TOK_WORD && t2->word() == "asrt") {
715 getToken(TOK_WORD);
716 emitOp(CAOS_CONSTINT, 1);
717 parseCondition();
718 int endreloc = current->newRelocation();
719 emitOp(CAOS_CJMP, endreloc);
720 emitCmd("cmd dbg: asrt");
721 current->fixRelocation(endreloc);
722 continue;
725 putBackToken(t);
726 emitExpr(readExpr(CI_COMMAND));
731 void caosScript::emitCmd(const char *name) {
732 const cmdinfo *ci = d->find_command(name);
733 emitOp(CAOS_CMD, d->cmd_index(ci));
734 if (ci->evalcost)
735 emitOp(CAOS_YIELD, ci->evalcost);
738 void CAOSExpression::eval(caosScript *scr, bool save_here) const {
739 boost::apply_visitor(evalVisit(scr, save_here), value);
742 void CAOSExpression::save(caosScript *scr) const {
743 boost::apply_visitor(saveVisit(scr), value);
746 int CAOSExpression::cost() const {
747 return boost::apply_visitor(costVisit(), value);
749 /* vim: set noet: */