source: branches/stable/AISC/aisc_interpreter.h

Last change on this file was 16763, checked in by westram, 6 years ago
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.0 KB
Line 
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
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(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
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
97template<typename T>
98inline 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
109static const int  LINEBUFSIZE  = 250;
110static const char ALIGN_MARKER = '\1';
111
112class 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
125public:
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
150class 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    }
159public:
160    LineQueue()
161        : count(0),
162          size(10),
163          queue((char**)malloc(size*sizeof(*queue)))
164    {}
165    ~LineQueue() {
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
192class 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
248public:
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
271class 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
303public:
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
335    void close_and_unlink() {
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
355struct Stack {
356    const Token *cursor;
357   
358    const Code  *pc;
359    hash  *hs;
360    Stack *next;
361};
362
363class Data : virtual Noncopyable {
364    TokenListBlock *rootBlock;
365    const Token    *cursor;
366public:
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
389class 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
468public:
469
470    static const Interpreter *instance;
471
472    Interpreter() {
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    }
493    ~Interpreter() {
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
Note: See TracBrowser for help on using the repository browser.