source: branches/profile/AISC/aisc_interpreter.h

Last change on this file was 10950, checked in by westram, 10 years ago
  • fix cppcheck warnings
    • renamed enum members hiding variables
    • reintroduced suppressions removed in [10946]
    • renamed function index()
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.8 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            realloc_unleaked(buf, size);
122            if (!buf) throw "out of memory";
123        }
124        buf[used++] = c;
125        if (c == ALIGN_MARKER) ++markers;
126    }
127
128    int length() const { return used; }
129    char *take() {
130        put(0);
131        char *b = buf;
132        clear();
133        return b;
134    }
135
136    bool needsAlignment() const { return markers; }
137};
138
139class LineQueue : virtual Noncopyable {
140    int    count;
141    int    size;
142    char **queue;
143
144    void clear() {
145        for (int i = 0; i<count; ++i) freenull(queue[i]);
146        count = 0;
147    }
148public:
149    LineQueue()
150        : count(0),
151          size(10),
152          queue((char**)malloc(size*sizeof(*queue)))
153    {}
154    ~LineQueue() {
155        clear();
156        free(queue);
157    }
158
159    bool empty() const { return count == 0; }
160
161    void add(char *line) {
162        if (count >= size) {
163            size  = size*3/2+1;
164            realloc_unleaked(queue, size*sizeof(*queue));
165            if (!queue) throw "out of memory";
166        }
167        aisc_assert(line[strlen(line)-1] == '\n');
168       
169        queue[count++] = line;
170    }
171
172    void alignInto(LineQueue& dest);
173
174    void flush(FILE *out) {
175        for (int i = 0; i<count; ++i) {
176            fputs(queue[i], out);
177        }
178        clear();
179    }
180};
181
182class Formatter {
183    char outtab[256]; // decode table for $x (0 = handle special, character to print otherwise)
184    int  tabstop;     // normal tabstop (for $t)
185    int  tabs[10];    // predefined tabs ($0..$9) - default to multiples of 'tabstop' if not overridden
186    int  column;      // position in line during printing
187    int  indent;      // extra indentation
188    bool printed_sth;
189
190    LineBuf currentLine;
191    LineQueue toAlign; 
192    LineQueue spool; 
193
194    void outputchar(char c) {
195        currentLine.put(c);
196    }
197
198    void print_char(char c) {
199        if (!printed_sth && (indent || column)) {
200            int ipos = indent*tabstop + column;
201            for (int i = 0; i<ipos; ++i) outputchar(' ');
202        }
203        outputchar(c);
204        column++;
205        printed_sth = true;
206    }
207
208    void tab_to_pos(int pos) {
209        if (pos>column) {
210            if (printed_sth) {
211                while (column < pos) {
212                    outputchar(' ');
213                    column++;
214                }
215            }
216            else {
217                column = pos;
218            }
219        }
220    }
221
222    void align() { if (!toAlign.empty()) toAlign.alignInto(spool); }
223   
224    void finish_line() {
225        outputchar('\n');
226        column      = 0;
227        printed_sth = false;
228
229        if (currentLine.needsAlignment()) {
230            toAlign.add(currentLine.take());
231        }
232        else {
233            align();
234            spool.add(currentLine.take());
235        }
236    }
237
238public:
239
240    Formatter();
241
242    void set_tabstop(int ts) {
243        tabstop = ts;
244        for (int i = 0; i <= 9; i++) {
245            tabs[i] = i * ts;
246        }
247    }
248    void set_tab(int idx, int pos) {
249        aisc_assert(idx >= 0 && idx<10);
250        tabs[idx] = pos;
251    }
252
253    int get_indent() const { return indent; }
254    void set_indent(int indent_) { indent = indent_; }
255
256    int write(const char *str);
257    void flush(FILE *out) { spool.flush(out); }
258    void final_flush(FILE *out) { align(); flush(out); }
259};
260
261class Output : virtual Noncopyable {
262    FILE *fp;
263    char *id;   // internal name used in AISC
264    char *name; // file-system name
265
266    bool     have_open_loc; // opened from user code ?
267    Location open_loc;
268
269    bool terminating;
270
271    Formatter formatter;
272
273    class PrintMaybe *maybe;
274
275    bool wasOpened() const { return fp && name; }
276
277    void close_file() {
278        if (wasOpened()) {
279            formatter.final_flush(fp);
280            if (have_open_loc && terminating) {
281                print_error(&open_loc, "file opened here");
282                print_error(&Location::guess_pc(), "is still open on exit");
283            }
284            fclose(fp);
285        }
286        fp = NULL;
287    }
288
289    void setup();
290    void cleanup();
291    void reuse() { cleanup(); setup(); }
292
293public:
294
295    Output() { terminating = false; setup(); }
296    ~Output() { terminating = true; cleanup(); }
297
298    bool inUse() const { return fp; }
299
300    void assign(FILE *fp_, const char *id_, const char *name_, const Location *openedAt) {
301        aisc_assert(!inUse());
302        aisc_assert(fp_);
303        aisc_assert(id_);
304        fp   = fp_;
305        id   = strdup(id_);
306        name = strdup(name_);
307
308        have_open_loc = openedAt;
309        if (openedAt) open_loc = *openedAt;
310    }
311    void assign(FILE *fp_, const char *id_, const char *name_) {
312        assign(fp_, id_, name_, (const Location*)NULL);
313    }
314    void assign(FILE *fp_, const char *id_, const char *name_, const Code *openedAt_) {
315        assign(fp_, id_, name_, &openedAt_->source);
316    }
317   
318    void assign_stdout(const char *id_) {
319        aisc_assert(!inUse());
320        fp   = stdout;
321        id   = strdup(id_);
322        name = NULL;
323    }
324
325    void close_and_unlink() {
326        close_file();
327        if (name) {
328            fprintf(stderr, "Unlinking %s\n", name);
329            unlink(name);
330        }
331        reuse();
332    }
333    void close() { reuse(); }
334
335    bool hasID(const char *Name) const { return id && strcmp(id, Name) == 0; }
336
337    int write(const char *line);
338    Formatter& get_formatter() { return formatter; }
339
340    void maybe_start();
341    int maybe_write(const char *line);
342    int maybe_end();
343};
344
345struct Stack {
346    const Token *cursor;
347   
348    const Code  *pc;
349    hash  *hs;
350    Stack *next;
351};
352
353class Data : virtual Noncopyable {
354    TokenListBlock *rootBlock;
355    const Token    *cursor;
356public:
357
358    Data() {
359        cursor    = NULL;
360        rootBlock = NULL;
361    }
362    ~Data() { delete rootBlock; }
363
364    void set_tokens(TokenListBlock *newRoot) {
365        delete rootBlock;
366        rootBlock = newRoot;
367    }
368    const TokenListBlock *get_tokens() const { return rootBlock; }
369
370    const Token *get_cursor() const { return cursor; }
371    void set_cursor(const Token *newCursor) { cursor = newCursor; }
372
373    const Token *find_token(const Token *curs, const char *str, LookupScope scope) const;
374    const Token *find_qualified_token(const char *str, LookupScope scope) const;
375
376    void dump_cursor_pos(FILE *out) const;
377};
378
379class Interpreter : virtual Noncopyable {
380    Parser parser;
381
382    Data data;             // currently loaded data
383
384    Code       *prg;       // the complete program
385    const Code *pc;        // current program counter
386    const Code *nextpc;
387
388    int    stack_size;
389    Stack *stack;
390    hash  *functions;      // and labels
391
392    Output  output[OPENFILES];    // open files
393    Output *current_output;       // pointer to one element of 'output'
394
395    static const int MAX_COMMANDS = 32;
396    class Command **command_table;
397    void command_table_setup(bool setup);
398
399    void pop();
400
401    Output *find_output_for_ID(const char *fileID) {
402        if (fileID) {
403            for (int i = 0; i < OPENFILES; i++) {
404                if (output[i].hasID(fileID)) return &output[i];
405            }
406        }
407        return NULL;
408    }
409    Formatter& current_formatter() { return current_output->get_formatter(); }
410
411    void write_var(const char *name, const char *val) { stack->hs->write(name, val); }
412    const char *read_var(const char *name) { return stack->hs->read(name); }
413
414    void define_fun(const char *name, const Code *co);
415    const Code *find_fun(const char *name);
416
417    int run_program();
418
419    void jump(const Code *to) { nextpc = to; }
420
421    int do_close(const char *str);
422    int do_create(const char *str);
423    int do_data(const char *str);
424    int do_dumpdata(const char *filename);
425    int do_error(const char *str) { print_error(at(), str); return 1; }
426    int do_exit() { nextpc = 0; return 0; }
427    int do_for(const char *str);
428    int do_gosub(const char *str);
429    int do_goto(const char *str);
430    int do_if(const char *str);
431    int do_moveto(const char *str);
432    int do_next();
433    int do_open(const char *str);
434    int do_out(const char *str);
435    int do_pop();
436    int do_push();
437    int do_return();
438    int do_set(const char *str);
439    int do_makeconst(const char *str);
440    int do_tab(const char *str);
441    int do_tabstop(const char *str);
442    int do_indent(const char *str);
443    int do_warning(const char *str) { print_warning(at(), str); return 0; }
444
445    int do_write_current(const char *str) { return current_output->write(str); }
446    int do_newline() { return current_output->write(""); }
447    int do_write_stdout(const char *str) { return output[0].write(str); }
448
449    int do_write_maybe_start() { current_output->maybe_start(); return 0; }
450    int do_write_maybe(const char *str) { return current_output->maybe_write(str); }
451    int do_write_maybe_end() { return current_output->maybe_end(); }
452   
453    int            compile_program();
454    const Command *find_command(const Code *co);
455
456    bool set_data(const char *filename, int offset_in_line);
457
458public:
459
460    static const Interpreter *instance;
461
462    Interpreter() {
463        pc     = NULL;
464        nextpc = NULL;
465
466        command_table_setup(true);
467
468        stack_size = 0;
469        functions = new hash(HASHSIZE);
470
471        prg   = NULL;
472        stack = NULL;
473
474        output[0].assign_stdout("stdout");
475        output[1].assign_stdout("*");
476        current_output = &output[0];
477
478        ASSERT_RESULT(int, 0, do_push());
479       
480        aisc_assert(!instance); // singleton!
481        instance = this;
482    }
483    ~Interpreter() {
484        aisc_assert(instance == this);
485        instance = NULL;
486
487        delete prg;
488        delete functions;
489        while (stack) pop();
490        command_table_setup(false);
491
492    }
493
494    int launch(int argc, char ** argv);
495
496
497    const Code *at() const { return pc; }
498    const Data& get_data() const { return data; }
499
500    const char *read_local(const char *key) const;
501    var_ref get_local(const char *key);
502};
503
504#else
505#error aisc.h included twice
506#endif // AISC_H
507
508
509
Note: See TracBrowser for help on using the repository browser.