source: tags/svn.1.5.4/AISC/aisc_interpreter.h

Last change on this file was 7623, checked in by westram, 13 years ago
  • merge from dev [7450] [7452] [7456] [7457] [7458] [7459] [7460] [7461] [7464] [7465] [7466] [7467] [7468] [7469] [7482]
    • tweaked compiler options
      • activated -Weffc++
        • postfilter warnings where Scott Meyers' advices are too general.
          • base classes should not always have virtual destructors, since that renders tiny classes useless and
          • members should not always be initialized via initialization list, since that often violates the DRY principle
        • fix gcc's inability to detect that Noncopyable implements a private copy-ctor and op=
        • this slows down complete ARB recompilation by ~5%
    • added -Wold-style-cast (inactive)
    • removed -Wno-non-template-friend added in [7447]
  • postcompile.pl
    • added option —original to show unmodified compiler output
  • declared op= for classes which had a copy-ctor
  • moved op= macros to arbtools.h
  • derived classes containing pointers from Noncopyable (use Noncopyable virtually) or
  • made them copyable if needed (awt_mask_item, KnownDB, Code, AWT_registered_itemtype, GEN_gene, PosGene, PartialSequence, PlugIn, Range, Convaln_exception)
  • other related changes
    • user mask destruction working now
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.7 KB
Line 
1// ================================================================ //
2//                                                                  //
3//   File      : aisc.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
26struct hash_entry {
27    char       *key;
28    char       *val;
29    hash_entry *next;
30};
31
32class var_ref {
33    hash_entry *e;
34
35    void const_violation();
36
37public:
38    var_ref() : e(NULL) {}
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 == NULL;
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  = NULL;
53            prot->next = e->next;
54
55            e->next = prot;
56        }
57    }
58
59    const char *read() const { return e ? e->val : NULL; }
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
73class 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
84public:
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
97static const int  LINEBUFSIZE  = 250;
98static const char ALIGN_MARKER = '\1';
99
100class LineBuf : virtual Noncopyable {
101    int   size;
102    int   used;
103    char *buf;
104    int   markers;
105
106    void clear() {
107        size    = 0;
108        used    = 0;
109        buf     = NULL;
110        markers = 0;
111    }
112
113public:
114    LineBuf() { clear(); }
115    ~LineBuf() { free(buf); }
116
117    void put(char c) {
118        if (used >= size) {
119            size = size*3/2+1;
120            if (size<LINEBUFSIZE) { size = LINEBUFSIZE; }
121            buf = (char*)realloc(buf, size);
122        }
123        buf[used++] = c;
124        if (c == ALIGN_MARKER) ++markers;
125    }
126
127    int length() const { return used; }
128    char *take() {
129        put(0);
130        char *b = buf;
131        clear();
132        return b;
133    }
134
135    bool needsAlignment() const { return markers; }
136};
137
138class LineQueue : virtual Noncopyable {
139    int    count;
140    int    size;
141    char **queue;
142
143    void clear() {
144        for (int i = 0; i<count; ++i) freenull(queue[i]);
145        count = 0;
146    }
147public:
148    LineQueue()
149        : count(0),
150          size(10),
151          queue((char**)malloc(size*sizeof(*queue)))
152    {}
153    ~LineQueue() {
154        clear();
155        free(queue);
156    }
157
158    bool empty() const { return count == 0; }
159
160    void add(char *line) {
161        if (count >= size) {
162            size  = size*3/2+1;
163            queue = (char**)realloc(queue, size*sizeof(*queue));
164        }
165        aisc_assert(line[strlen(line)-1] == '\n');
166       
167        queue[count++] = line;
168    }
169
170    void alignInto(LineQueue& dest);
171
172    void flush(FILE *out) {
173        for (int i = 0; i<count; ++i) {
174            fputs(queue[i], out);
175        }
176        clear();
177    }
178};
179
180class Formatter {
181    char outtab[256]; // decode table for $x (0 = handle special, character to print otherwise)
182    int  tabstop;     // normal tabstop (for $t)
183    int  tabs[10];    // predefined tabs ($0..$9) - default to multiples of 'tabstop' if not overridden
184    int  column;      // position in line during printing
185    int  indent;      // extra indentation
186    bool printed_sth;
187
188    LineBuf currentLine;
189    LineQueue toAlign; 
190    LineQueue spool; 
191
192    void outputchar(char c) {
193        currentLine.put(c);
194    }
195
196    void print_char(char c) {
197        if (!printed_sth && (indent || column)) {
198            int ipos = indent*tabstop + column;
199            for (int i = 0; i<ipos; ++i) outputchar(' ');
200        }
201        outputchar(c);
202        column++;
203        printed_sth = true;
204    }
205
206    void tab_to_pos(int pos) {
207        if (pos>column) {
208            if (printed_sth) {
209                while (column < pos) {
210                    outputchar(' ');
211                    column++;
212                }
213            }
214            else {
215                column = pos;
216            }
217        }
218    }
219
220    void align() { if (!toAlign.empty()) toAlign.alignInto(spool); }
221   
222    void finish_line() {
223        outputchar('\n');
224        column      = 0;
225        printed_sth = false;
226
227        if (currentLine.needsAlignment()) {
228            toAlign.add(currentLine.take());
229        }
230        else {
231            align();
232            spool.add(currentLine.take());
233        }
234    }
235
236public:
237
238    Formatter();
239
240    void set_tabstop(int ts) {
241        tabstop = ts;
242        for (int i = 0; i <= 9; i++) {
243            tabs[i] = i * ts;
244        }
245    }
246    void set_tab(int idx, int pos) {
247        aisc_assert(idx >= 0 && idx<10);
248        tabs[idx] = pos;
249    }
250
251    int get_indent() const { return indent; }
252    void set_indent(int indent_) { indent = indent_; }
253
254    int write(const char *str);
255    void flush(FILE *out) { spool.flush(out); }
256    void final_flush(FILE *out) { align(); flush(out); }
257};
258
259class Output : virtual Noncopyable {
260    FILE *fp;
261    char *id;   // internal name used in AISC
262    char *name; // file-system name
263
264    bool     have_open_loc; // opened from user code ?
265    Location open_loc;
266
267    bool terminating;
268
269    Formatter formatter;
270
271    class PrintMaybe *maybe;
272
273    bool wasOpened() const { return fp && name; }
274
275    void close_file() {
276        if (wasOpened()) {
277            formatter.final_flush(fp);
278            if (have_open_loc && terminating) {
279                print_error(&open_loc, "file opened here");
280                print_error(&Location::guess_pc(), "is still open on exit");
281            }
282            fclose(fp);
283        }
284        fp = NULL;
285    }
286
287    void setup();
288    void cleanup();
289    void reuse() { cleanup(); setup(); }
290
291public:
292
293    Output() { terminating = false; setup(); }
294    ~Output() { terminating = true; cleanup(); }
295
296    bool inUse() const { return fp; }
297
298    void assign(FILE *fp_, const char *id_, const char *name_, const Location *openedAt) {
299        aisc_assert(!inUse());
300        aisc_assert(fp_);
301        aisc_assert(id_);
302        fp   = fp_;
303        id   = strdup(id_);
304        name = strdup(name_);
305
306        have_open_loc = openedAt;
307        if (openedAt) open_loc = *openedAt;
308    }
309    void assign(FILE *fp_, const char *id_, const char *name_) {
310        assign(fp_, id_, name_, (const Location*)NULL);
311    }
312    void assign(FILE *fp_, const char *id_, const char *name_, const Code *openedAt_) {
313        assign(fp_, id_, name_, &openedAt_->source);
314    }
315   
316    void assign_stdout(const char *id_) {
317        aisc_assert(!inUse());
318        fp   = stdout;
319        id   = strdup(id_);
320        name = NULL;
321    }
322
323    void close_and_unlink() {
324        close_file();
325        if (name) {
326            fprintf(stderr, "Unlinking %s\n", name);
327            unlink(name);
328        }
329        reuse();
330    }
331    void close() { reuse(); }
332
333    bool hasID(const char *Name) const { return id && strcmp(id, Name) == 0; }
334
335    int write(const char *line);
336    Formatter& get_formatter() { return formatter; }
337
338    void maybe_start();
339    int maybe_write(const char *line);
340    int maybe_end();
341};
342
343struct Stack {
344    const Token *cursor;
345   
346    const Code  *pc;
347    hash  *hs;
348    Stack *next;
349};
350
351class Data : virtual Noncopyable {
352    TokenListBlock *rootBlock;
353    const Token    *cursor;
354public:
355
356    Data() {
357        cursor    = NULL;
358        rootBlock = NULL;
359    }
360    ~Data() { delete rootBlock; }
361
362    void set_tokens(TokenListBlock *newRoot) {
363        delete rootBlock;
364        rootBlock = newRoot;
365    }
366    const TokenListBlock *get_tokens() const { return rootBlock; }
367
368    const Token *get_cursor() const { return cursor; }
369    void set_cursor(const Token *newCursor) { cursor = newCursor; }
370
371    const Token *find_token(const Token *curs, const char *str, LookupScope scope) const;
372    const Token *find_qualified_token(const char *str, LookupScope scope) const;
373
374    void dump_cursor_pos(FILE *out) const;
375};
376
377class Interpreter : virtual Noncopyable {
378    Parser parser;
379
380    Data data;             // currently loaded data
381
382    Code       *prg;       // the complete program
383    const Code *pc;        // current program counter
384    const Code *nextpc;
385
386    int    stack_size;
387    Stack *stack;
388    hash  *functions;      // and labels
389
390    Output  output[OPENFILES];    // open files
391    Output *current_output;       // pointer to one element of 'output'
392
393    static const int MAX_COMMANDS = 32;
394    class Command **command_table;
395    void command_table_setup(bool setup);
396
397    void pop();
398
399    Output *find_output_for_ID(const char *fileID) {
400        if (fileID) {
401            for (int i = 0; i < OPENFILES; i++) {
402                if (output[i].hasID(fileID)) return &output[i];
403            }
404        }
405        return NULL;
406    }
407    Formatter& current_formatter() { return current_output->get_formatter(); }
408
409    void write_var(const char *name, const char *val) { stack->hs->write(name, val); }
410    const char *read_var(const char *name) { return stack->hs->read(name); }
411
412    void define_fun(const char *name, const Code *co);
413    const Code *find_fun(const char *name);
414
415    int run_program();
416
417    void jump(const Code *to) { nextpc = to; }
418
419    int do_close(const char *str);
420    int do_create(const char *str);
421    int do_data(const char *str);
422    int do_dumpdata(const char *filename);
423    int do_error(const char *str) { print_error(at(), str); return 1; }
424    int do_exit() { nextpc = 0; return 0; }
425    int do_for(const char *str);
426    int do_gosub(const char *str);
427    int do_goto(const char *str);
428    int do_if(const char *str);
429    int do_moveto(const char *str);
430    int do_next();
431    int do_open(const char *str);
432    int do_out(const char *str);
433    int do_pop();
434    int do_push();
435    int do_return();
436    int do_set(const char *str);
437    int do_makeconst(const char *str);
438    int do_tab(const char *str);
439    int do_tabstop(const char *str);
440    int do_indent(const char *str);
441    int do_warning(const char *str) { print_warning(at(), str); return 0; }
442
443    int do_write_current(const char *str) { return current_output->write(str); }
444    int do_newline() { return current_output->write(""); }
445    int do_write_stdout(const char *str) { return output[0].write(str); }
446
447    int do_write_maybe_start() { current_output->maybe_start(); return 0; }
448    int do_write_maybe(const char *str) { return current_output->maybe_write(str); }
449    int do_write_maybe_end() { return current_output->maybe_end(); }
450   
451    int            compile_program();
452    const Command *find_command(const Code *co);
453
454    bool set_data(const char *filename, int offset_in_line);
455
456public:
457
458    static const Interpreter *instance;
459
460    Interpreter() {
461        pc     = NULL;
462        nextpc = NULL;
463
464        command_table_setup(true);
465
466        stack_size = 0;
467        functions = new hash(HASHSIZE);
468
469        prg   = NULL;
470        stack = NULL;
471
472        output[0].assign_stdout("stdout");
473        output[1].assign_stdout("*");
474        current_output = &output[0];
475
476        ASSERT_RESULT(int, 0, do_push());
477       
478        aisc_assert(!instance); // singleton!
479        instance = this;
480    }
481    ~Interpreter() {
482        aisc_assert(instance == this);
483        instance = NULL;
484
485        delete prg;
486        delete functions;
487        while (stack) pop();
488        command_table_setup(false);
489
490    }
491
492    int launch(int argc, char ** argv);
493
494
495    const Code *at() const { return pc; }
496    const Data& get_data() const { return data; }
497
498    const char *read_local(const char *key) const;
499    var_ref get_local(const char *key);
500};
501
502#else
503#error aisc.h included twice
504#endif // AISC_H
505
506
507
Note: See TracBrowser for help on using the repository browser.