add some hacky code to allow passing sfc files with -b
[openc2e.git] / caosScript.h
blobca472677dcd1e209abbf77e387346154424b39d9
1 /*
2 * caosScript.h
3 * openc2e
5 * Created by Alyssa Milburn on Tue May 25 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 #ifndef CAOSSCRIPT_H
21 #define CAOSSCRIPT_H
23 #include <vector>
24 #include <list>
25 #include <string>
26 #include <istream>
27 #include <map>
28 #include "caosVar.h"
29 #include <cassert>
30 #include "openc2e.h"
31 #include "bytecode.h"
32 #include "caosVar.h"
33 #include "dialect.h"
34 #include "token.h"
35 #include "shared_str.h"
38 class Agent;
40 struct toktrace {
41 unsigned short width;
42 unsigned short lineno;
44 toktrace(unsigned short w, unsigned short l) : width(w), lineno(l) { }
45 private:
46 FRIEND_SERIALIZE(toktrace);
47 toktrace() { }
50 struct script {
51 protected:
52 FRIEND_SERIALIZE(script);
54 bool linked;
56 // position 0 is reserved in the below vector
57 // relocations[-relocid] is the target address for relocation relocid
58 // will be 0 if unresolved
59 std::vector<int> relocations;
60 // map of name -> (address|relocation)
61 std::map<std::string, int> labels;
62 script() {}
63 public:
64 // ops[0] is initted to a nop, as address 0 is reserved for a flag value
65 // in the relocation vector
66 std::vector<caosOp> ops;
67 // table of all non-trivial constants in the script
68 // small immediates integers are done with CAOS_CONSTINT
69 // mostly for strings and floats
70 std::vector<caosVar> consts;
71 // because caosVar doesn't store bytestrings, we store them in a separate
72 // table
73 std::vector<bytestring_t> bytestrs;
74 // a normalized copy of the script source. this is used for error tracing
75 shared_str code;
76 shared_ptr<std::vector<toktrace> > tokinfo;
78 public:
79 int fmly, gnus, spcs, scrp;
80 const class Dialect *dialect;
81 const Dialect *getDialect() const { return dialect; };
83 std::string filename;
85 caosOp getOp(int idx) const {
86 assert (idx >= 0);
87 return (size_t)idx >= ops.size() ? caosOp(CAOS_DIE, -1, -1) : ops[idx];
90 int scriptLength() const {
91 return ops.size();
94 caosVar getConstant(int idx) const {
95 if (idx < 0 || (size_t)idx >= consts.size()) {
96 throw caosException(boost::str(
97 boost::format("Internal error: const %d out of range") % idx
98 ));
100 return consts[idx];
103 bytestring_t getBytestr(int idx) const {
104 if (idx < 0 || (size_t)idx >= bytestrs.size()) {
105 throw caosException(boost::str(
106 boost::format("Internal error: const %d out of range") % idx
109 return bytestrs[idx];
112 std::map<std::string, int> gsub;
113 int getNextIndex() { return ops.size(); }
114 // add op as the next opcode
115 script(const Dialect *v, const std::string &fn,
116 int fmly_, int gnus_, int spcs_, int scrp_);
117 script(const Dialect *v, const std::string &fn);
118 ~script();
119 std::string dump();
120 // std::string dumpLine(unsigned int);
122 void link();
124 int newRelocation() {
125 assert (!linked);
126 int idx = relocations.size();
127 relocations.push_back(0);
128 return -idx;
131 void fixRelocation(int r, int p) {
132 assert (!linked);
133 assert (r < 0);
134 r = -r;
135 assert (relocations[r] == 0);
136 // check for a loop
137 int i = p;
138 while (i < 0) {
139 i = -i;
140 if (i == r)
141 throw creaturesException("relocation loop found");
142 i = relocations[i];
145 relocations[r] = p;
148 // fix relocation r to point to the next op to be emitted
149 void fixRelocation(int r) {
150 fixRelocation(r, getNextIndex());
153 // find the address of the given label, could be a relocation
154 int getLabel(const std::string &label) {
155 if (labels.find(label) == labels.end())
156 labels[label] = newRelocation();
157 return labels[label];
160 // fix a label to the end of the current op string
161 void affixLabel(const std::string &label) {
162 int reloc = getLabel(label);
163 if (reloc > 0)
164 throw caosException(std::string("Label ") + label + " redefined");
165 fixRelocation(reloc);
166 labels[label] = getNextIndex();
169 void emitOp(opcode_t op, int argument);
173 // parser tree
175 class caosScript;
177 class CAOSExpression;
179 struct CAOSCmd {
180 const cmdinfo *op;
181 std::vector<boost::shared_ptr<CAOSExpression> > arguments;
182 int traceidx;
183 CAOSCmd() { op = 0; traceidx = -1; }
184 CAOSCmd(const CAOSCmd &c) : op(c.op), arguments(c.arguments) { }
187 struct CAOSExpression {
188 boost::variant<CAOSCmd, caosVar, bytestring_t> value;
189 int traceidx;
190 void eval(caosScript *scr, bool save_here) const;
191 void save(caosScript *scr) const;
192 int cost() const;
194 CAOSExpression(const CAOSExpression &e) : value(e.value), traceidx(e.traceidx) { }
195 CAOSExpression(int idx, const CAOSCmd &c) : value(c), traceidx(idx) { boost::get<CAOSCmd>(value).traceidx = traceidx; }
196 CAOSExpression(int idx, const caosVar &c) : value(c), traceidx(idx) { }
197 CAOSExpression(int idx, const bytestring_t &c) : value(c), traceidx(idx) { }
200 class caosScript;
202 struct costVisit : public boost::static_visitor<int> {
203 public:
204 costVisit() {}
205 int operator()(const CAOSCmd &cmd) const;
207 int operator()(const caosVar &v) const { (void)v; return 0; }
208 int operator()(const bytestring_t &v) const { (void)v;return 0; }
211 struct saveVisit : public boost::static_visitor<void> {
212 private:
213 caosScript *scr;
214 public:
215 saveVisit(class caosScript *s);
216 void operator()(const CAOSCmd &cmd) const;
218 void operator()(const caosVar &v) const { (void)v; }
219 void operator()(const bytestring_t &v) const { (void)v; }
222 struct evalVisit : public boost::static_visitor<void> {
223 private:
224 caosScript *scr;
225 bool save_here;
226 public:
227 evalVisit(caosScript *s, bool save_here);
228 void operator()(const CAOSCmd &cmd) const;
229 void operator()(const caosVar &v) const;
230 void operator()(const bytestring_t &bs) const;
233 class caosScript { //: Collectable {
234 public:
235 const Dialect *d;
236 std::string filename;
237 shared_ptr<script> installer, removal;
238 std::vector<shared_ptr<script> > scripts;
239 shared_ptr<script> current;
241 caosScript(const std::string &dialect, const std::string &fn);
242 caosScript() { d = NULL; }
243 void parse(std::istream &in);
244 ~caosScript();
245 void installScripts();
246 void installInstallScript(unsigned char family, unsigned char genus, unsigned short species, unsigned short eventid);
247 protected:
248 int readCond();
249 void parseCondition();
250 void emitOp(opcode_t op, int argument);
251 void emitCmd(const char *name);
252 boost::shared_ptr<CAOSExpression> readExpr(const enum ci_type xtype);
253 void emitExpr(boost::shared_ptr<CAOSExpression> ce);
254 const cmdinfo *readCommand(class token *t, const std::string &prefix);
255 void parseloop(int state, void *info);
257 shared_ptr<std::vector<token> > tokens;
258 int curindex; // index to the next token to be read
259 int errindex; // index to the token to report parse errors on
260 int traceindex; // index to the token to report runtime errors on
261 int enumdepth;
262 // deprecated support functions
263 token *tokenPeek();
264 void putBackToken(token *);
265 token *getToken(toktype expected = ANYTOKEN);
267 friend struct saveVisit;
268 friend struct evalVisit;
271 #endif
272 /* vim: set noet: */