ARB
aisc_interpreter.h
Go to the documentation of this file.
1 // ================================================================ //
2 // //
3 // File : aisc_interpreter.h //
4 // Purpose : //
5 // //
6 // Institute of Microbiology (Technical University Munich) //
7 // http://www.arb-home.de/ //
8 // //
9 // ================================================================ //
10 
11 #ifndef AISC_H
12 #define AISC_H
13 
14 #ifndef AISC_PROTO_H
15 #include "aisc_proto.h"
16 #endif
17 #ifndef AISC_PARSER_H
18 #include "aisc_parser.h"
19 #endif
20 #ifndef _UNISTD_H
21 #include <unistd.h>
22 #endif
23 
24 // ------------------------------------------------------------
25 
26 struct hash_entry {
27  char *key;
28  char *val;
30 };
31 
32 class var_ref {
33  hash_entry *e;
34 
35  void const_violation();
36 
37 public:
38  var_ref() : e(NULp) {}
39  var_ref(hash_entry *e_) : e(e_) {}
40 
41  operator bool() const { return e; } // refer to existing variable ?
42 
43  bool write_protected() const {
44  hash_entry *prot = e->next;
45  return prot && strcmp(prot->key, e->key) == 0 && !prot->val;
46  }
47  void write_protect() {
48  if (!write_protected()) {
49  hash_entry *prot = (hash_entry *)calloc(sizeof(hash_entry), 1);
50 
51  prot->key = strdup(e->key);
52  prot->val = NULp;
53  prot->next = e->next;
54 
55  e->next = prot;
56  }
57  }
58 
59  const char *read() const { return e ? e->val : NULp; }
60  int write(const char *val) __ATTR__USERESULT {
61  aisc_assert(e);
62 
63  if (write_protected()) {
64  const_violation();
65  return -1;
66  }
67  freeset(e->val, nulldup(val));
68  return 0;
69  }
70 
71 };
72 
73 class hash : virtual Noncopyable {
74  int size;
75  hash_entry **entries;
76 
77  int Index(const char *key) const;
78 
79  const hash_entry *find_entry(const char *key, int idx) const;
80  hash_entry *find_entry(const char *key, int idx) {
81  return const_cast<hash_entry*>(const_cast<const hash*>(this)->find_entry(key, idx));
82  }
83 
84 public:
85  hash(int size_);
86  ~hash();
87 
88  var_ref ref(const char *key) { return var_ref(find_entry(key, Index(key))); }
89  const var_ref ref(const char *key) const { return const_cast<hash*>(this)->ref(key); }
90 
91  const char *read(const char *key) const { return ref(key).read(); }
92  void write(const char *key, const char *val);
93 };
94 
95 // ------------------------------------------------------------
96 
97 template<typename T>
98 inline void realloc_unleaked(T*& ptr, size_t new_size) {
99  T *new_ptr = (T*)realloc(ptr, new_size);
100  if (!new_ptr) {
101  free(ptr);
102  throw "out of memory";
103  }
104  ptr = new_ptr;
105 }
106 
107 // ------------------------------------------------------------
108 
109 static const int LINEBUFSIZE = 250;
110 static const char ALIGN_MARKER = '\1';
111 
112 class LineBuf : virtual Noncopyable {
113  int size;
114  int used;
115  char *buf;
116  int markers;
117 
118  void clear() {
119  size = 0;
120  used = 0;
121  buf = NULp;
122  markers = 0;
123  }
124 
125 public:
126  LineBuf() { clear(); }
127  ~LineBuf() { free(buf); }
128 
129  void put(char c) {
130  if (used >= size) {
131  size = size*3/2+1;
132  if (size<LINEBUFSIZE) { size = LINEBUFSIZE; }
133  realloc_unleaked(buf, size);
134  }
135  buf[used++] = c;
136  if (c == ALIGN_MARKER) ++markers;
137  }
138 
139  int length() const { return used; }
140  char *take() {
141  put(0);
142  char *b = buf;
143  clear();
144  return b;
145  }
146 
147  bool needsAlignment() const { return markers; }
148 };
149 
150 class LineQueue : virtual Noncopyable {
151  int count;
152  int size;
153  char **queue;
154 
155  void clear() {
156  for (int i = 0; i<count; ++i) freenull(queue[i]);
157  count = 0;
158  }
159 public:
161  : count(0),
162  size(10),
163  queue((char**)malloc(size*sizeof(*queue)))
164  {}
166  clear();
167  free(queue);
168  }
169 
170  bool empty() const { return count == 0; }
171 
172  void add(char *line) {
173  if (count >= size) {
174  size = size*3/2+1;
175  realloc_unleaked(queue, size*sizeof(*queue));
176  }
177  aisc_assert(line[strlen(line)-1] == '\n');
178 
179  queue[count++] = line;
180  }
181 
182  void alignInto(LineQueue& dest);
183 
184  void flush(FILE *out) {
185  for (int i = 0; i<count; ++i) {
186  fputs(queue[i], out);
187  }
188  clear();
189  }
190 };
191 
192 class Formatter {
193  char outtab[256]; // decode table for $x (0 = handle special, character to print otherwise)
194  int tabstop; // normal tabstop (for $t)
195  int tabs[10]; // predefined tabs ($0..$9) - default to multiples of 'tabstop' if not overridden
196  int column; // position in line during printing
197  int indent; // extra indentation
198  bool printed_sth;
199 
200  LineBuf currentLine;
201  LineQueue toAlign;
202  LineQueue spool;
203 
204  void outputchar(char c) {
205  currentLine.put(c);
206  }
207 
208  void print_char(char c) {
209  if (!printed_sth && (indent || column)) {
210  int ipos = indent*tabstop + column;
211  for (int i = 0; i<ipos; ++i) outputchar(' ');
212  }
213  outputchar(c);
214  column++;
215  printed_sth = true;
216  }
217 
218  void tab_to_pos(int pos) {
219  if (pos>column) {
220  if (printed_sth) {
221  while (column < pos) {
222  outputchar(' ');
223  column++;
224  }
225  }
226  else {
227  column = pos;
228  }
229  }
230  }
231 
232  void align() { if (!toAlign.empty()) toAlign.alignInto(spool); }
233 
234  void finish_line() {
235  outputchar('\n');
236  column = 0;
237  printed_sth = false;
238 
239  if (currentLine.needsAlignment()) {
240  toAlign.add(currentLine.take());
241  }
242  else {
243  align();
244  spool.add(currentLine.take());
245  }
246  }
247 
248 public:
249 
250  Formatter();
251 
252  void set_tabstop(int ts) {
253  tabstop = ts;
254  for (int i = 0; i <= 9; i++) {
255  tabs[i] = i * ts;
256  }
257  }
258  void set_tab(int idx, int pos) {
259  aisc_assert(idx >= 0 && idx<10);
260  tabs[idx] = pos;
261  }
262 
263  int get_indent() const { return indent; }
264  void set_indent(int indent_) { indent = indent_; }
265 
266  int write(const char *str);
267  void flush(FILE *out) { spool.flush(out); }
268  void final_flush(FILE *out) { align(); flush(out); }
269 };
270 
271 class Output : virtual Noncopyable {
272  FILE *fp;
273  char *id; // internal name used in AISC
274  char *name; // file-system name
275 
276  bool have_open_loc; // opened from user code ?
277  Location open_loc;
278 
279  bool terminating;
280 
281  Formatter formatter;
282 
283  class PrintMaybe *maybe;
284 
285  bool wasOpened() const { return fp && name; }
286 
287  void close_file() {
288  if (wasOpened()) {
289  formatter.final_flush(fp);
290  if (have_open_loc && terminating) {
291  print_error(&open_loc, "file opened here");
292  print_error(&Location::guess_pc(), "is still open on exit");
293  }
294  fclose(fp);
295  }
296  fp = NULp;
297  }
298 
299  void setup();
300  void cleanup();
301  void reuse() { cleanup(); setup(); }
302 
303 public:
304 
305  Output() { terminating = false; setup(); }
306  ~Output() { terminating = true; cleanup(); }
307 
308  bool inUse() const { return fp; }
309 
310  void assign(FILE *fp_, const char *id_, const char *name_, const Location *openedAt) {
311  aisc_assert(!inUse());
312  aisc_assert(fp_);
313  aisc_assert(id_);
314  fp = fp_;
315  id = strdup(id_);
316  name = strdup(name_);
317 
318  have_open_loc = openedAt;
319  if (openedAt) open_loc = *openedAt;
320  }
321  void assign(FILE *fp_, const char *id_, const char *name_) {
322  assign(fp_, id_, name_, (const Location*)NULp);
323  }
324  void assign(FILE *fp_, const char *id_, const char *name_, const Code *openedAt_) {
325  assign(fp_, id_, name_, &openedAt_->source);
326  }
327 
328  void assign_stdout(const char *id_) {
329  aisc_assert(!inUse());
330  fp = stdout;
331  id = strdup(id_);
332  name = NULp;
333  }
334 
336  close_file();
337  if (name) {
338  fprintf(stderr, "Unlinking %s\n", name);
339  unlink(name);
340  }
341  reuse();
342  }
343  void close() { reuse(); }
344 
345  bool hasID(const char *Name) const { return id && strcmp(id, Name) == 0; }
346 
347  int write(const char *line);
348  Formatter& get_formatter() { return formatter; }
349 
350  void maybe_start();
351  int maybe_write(const char *line);
352  int maybe_end();
353 };
354 
355 struct Stack {
356  const Token *cursor;
357 
358  const Code *pc;
361 };
362 
363 class Data : virtual Noncopyable {
364  TokenListBlock *rootBlock;
365  const Token *cursor;
366 public:
367 
368  Data() {
369  cursor = NULp;
370  rootBlock = NULp;
371  }
372  ~Data() { delete rootBlock; }
373 
374  void set_tokens(TokenListBlock *newRoot) {
375  delete rootBlock;
376  rootBlock = newRoot;
377  }
378  const TokenListBlock *get_tokens() const { return rootBlock; }
379 
380  const Token *get_cursor() const { return cursor; }
381  void set_cursor(const Token *newCursor) { cursor = newCursor; }
382 
383  const Token *find_token(const Token *curs, const char *str, LookupScope scope) const;
384  const Token *find_qualified_token(const char *str, LookupScope scope) const;
385 
386  void dump_cursor_pos(FILE *out) const;
387 };
388 
389 class Interpreter : virtual Noncopyable {
390  Parser parser;
391 
392  Data data; // currently loaded data
393 
394  Code *prg; // the complete program
395  const Code *pc; // current program counter
396  const Code *nextpc;
397 
398  int stack_size;
399  Stack *stack;
400  hash *functions; // and labels
401 
402  Output output[OPENFILES]; // open files
403  Output *current_output; // pointer to one element of 'output'
404 
405  static const int MAX_COMMANDS = 32;
406  class Command **command_table;
407  void command_table_setup(bool setup);
408 
409  void pop();
410 
411  Output *find_output_for_ID(const char *fileID) {
412  if (fileID) {
413  for (int i = 0; i < OPENFILES; i++) {
414  if (output[i].hasID(fileID)) return &output[i];
415  }
416  }
417  return NULp;
418  }
419  Formatter& current_formatter() { return current_output->get_formatter(); }
420 
421  void write_var(const char *name, const char *val) { stack->hs->write(name, val); }
422  const char *read_var(const char *name) { return stack->hs->read(name); }
423 
424  void define_fun(const char *name, const Code *co);
425  const Code *find_fun(const char *name);
426 
427  int run_program();
428 
429  void jump(const Code *to) { nextpc = to; }
430 
431  int do_close(const char *str);
432  int do_create(const char *str);
433  int do_data(const char *str);
434  int do_dumpdata(const char *filename);
435  int do_error(const char *str) { print_error(at(), str); return 1; }
436  int do_exit() { nextpc = NULp; return 0; }
437  int do_for(const char *str);
438  int do_gosub(const char *str);
439  int do_goto(const char *str);
440  int do_if(const char *str);
441  int do_moveto(const char *str);
442  int do_next();
443  int do_open(const char *str);
444  int do_out(const char *str);
445  int do_pop();
446  int do_push();
447  int do_return();
448  int do_set(const char *str);
449  int do_makeconst(const char *str);
450  int do_tab(const char *str);
451  int do_tabstop(const char *str);
452  int do_indent(const char *str);
453  int do_warning(const char *str) { print_warning(at(), str); return 0; }
454 
455  int do_write_current(const char *str) { return current_output->write(str); }
456  int do_newline() { return current_output->write(""); }
457  int do_write_stdout(const char *str) { return output[0].write(str); }
458 
459  int do_write_maybe_start() { current_output->maybe_start(); return 0; }
460  int do_write_maybe(const char *str) { return current_output->maybe_write(str); }
461  int do_write_maybe_end() { return current_output->maybe_end(); }
462 
463  int compile_program();
464  const Command *find_command(const Code *co);
465 
466  bool set_data(const char *filename, int offset_in_line);
467 
468 public:
469 
470  static const Interpreter *instance;
471 
473  pc = NULp;
474  nextpc = NULp;
475 
476  command_table_setup(true);
477 
478  stack_size = 0;
479  functions = new hash(HASHSIZE);
480 
481  prg = NULp;
482  stack = NULp;
483 
484  output[0].assign_stdout("stdout");
485  output[1].assign_stdout("*");
486  current_output = &output[0];
487 
488  ASSERT_RESULT(int, 0, do_push());
489 
490  aisc_assert(!instance); // singleton!
491  instance = this;
492  }
494  aisc_assert(instance == this);
495  instance = NULp;
496 
497  delete prg;
498  delete functions;
499  while (stack) pop();
500  command_table_setup(false);
501 
502  }
503 
504  int launch(int argc, char ** argv);
505 
506 
507  const Code *at() const { return pc; }
508  const Data& get_data() const { return data; }
509 
510  const char *read_local(const char *key) const;
511  var_ref get_local(const char *key);
512 };
513 
514 #else
515 #error aisc.h included twice
516 #endif // AISC_H
517 
518 
519 
void set_cursor(const Token *newCursor)
Location source
Definition: aisc_parser.h:39
const Token * cursor
char * val
int write(const char *line)
Definition: aisc.c:205
void do_indent(ostream &out, int indent)
Definition: SEC_io.cxx:44
const Code * at() const
LookupScope
Definition: aisc_def.h:23
int length() const
void set_indent(int indent_)
int write(const char *str)
Definition: aisc.c:246
bool write_protected() const
bool inUse() const
void set_tab(int idx, int pos)
#define ASSERT_RESULT(Type, Expected, Expr)
Definition: arb_assert.h:336
hash(int size_)
Definition: aisc_mix.c:205
int maybe_end()
Definition: aisc.c:196
static const Interpreter * instance
void flush(FILE *out)
void write(const char *key, const char *val)
Definition: aisc_mix.c:242
void put(char c)
int get_indent() const
int write(const char *val) __ATTR__USERESULT
const Token * get_cursor() const
var_ref ref(const char *key)
void close()
var_ref(hash_entry *e_)
void write_protect()
const Token * find_token(const Token *curs, const char *str, LookupScope scope) const
Definition: aisc_var_ref.c:81
var_ref get_local(const char *key)
Definition: aisc_mix.c:258
hash_entry * next
void alignInto(LineQueue &dest)
Definition: aisc.c:55
void realloc_unleaked(T *&ptr, size_t new_size)
#define print_error(code_or_loc, err)
Definition: aisc_def.h:47
char * take()
void set_tokens(TokenListBlock *newRoot)
char * key
Stack * next
void maybe_start()
Definition: aisc.c:185
~hash()
Definition: aisc_mix.c:209
static const Location & guess_pc()
Definition: aisc_commands.c:17
void close_and_unlink()
#define OPENFILES
Definition: aisc_def.h:19
void assign_stdout(const char *id_)
const char * read(const char *key) const
fputs(TRACE_PREFIX, stderr)
hash * hs
int maybe_write(const char *line)
Definition: aisc.c:188
static void cleanup()
Definition: arb_a2ps.c:916
const Code * pc
Definition: output.h:122
#define __ATTR__USERESULT
Definition: attributes.h:58
#define HASHSIZE
Definition: aisc_def.h:20
const char * read() const
void assign(FILE *fp_, const char *id_, const char *name_)
const Data & get_data() const
void flush(FILE *out)
const var_ref ref(const char *key) const
bool needsAlignment() const
void add(char *line)
static int line
Definition: arb_a2ps.c:296
#define NULp
Definition: cxxforward.h:116
static const int LINEBUFSIZE
int launch(int argc, char **argv)
Definition: aisc.c:314
void set_tabstop(int ts)
void assign(FILE *fp_, const char *id_, const char *name_, const Code *openedAt_)
const char * read_local(const char *key) const
Definition: aisc_mix.c:266
Definition: trnsprob.h:20
Formatter & get_formatter()
const TokenListBlock * get_tokens() const
void dump_cursor_pos(FILE *out) const
Definition: aisc_var_ref.c:281
#define aisc_assert(cond)
Definition: aisc_def.h:11
Formatter()
Definition: aisc.c:218
bool empty() const
bool hasID(const char *Name) const
#define print_warning(code_or_loc, err)
Definition: aisc_def.h:48
static const char ALIGN_MARKER
void final_flush(FILE *out)
const Token * find_qualified_token(const char *str, LookupScope scope) const
Definition: aisc_var_ref.c:121
Definition: output.h:28
void assign(FILE *fp_, const char *id_, const char *name_, const Location *openedAt)
const Location & pc() const