source: trunk/AISC/aisc.c

Last change on this file was 18730, checked in by westram, 3 years ago
  • remove trailing whitespace from c source.
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.0 KB
Line 
1// ================================================================
2/*                                                                  */
3//   File      : aisc.c
4//   Purpose   : ARB integrated source compiler
5/*                                                                  */
6//   Institute of Microbiology (Technical University Munich)
7//   http://www.arb-home.de
8/*                                                                  */
9// ================================================================
10
11#include "aisc_interpreter.h"
12#include <cctype>
13#include <list>
14#include <string>
15
16using namespace std;
17
18// AISC_MKPT_PROMOTE:#ifndef AISC_DEF_H
19// AISC_MKPT_PROMOTE:#include "aisc_def.h"
20// AISC_MKPT_PROMOTE:#endif
21
22char *read_aisc_file(const char *path, const Location *loc) {
23    char *buffer = NULp;
24    FILE *input  = fopen(path, "rt");
25
26    if (!input) {
27        printf_error(loc, "file '%s' not found", path);
28    }
29    else {
30        if (fseek(input, 0, 2)==-1) {
31            printf_error(loc, "file '%s' not seekable", path);
32        }
33        else {
34            int data_size = (int)ftell(input);
35
36            if (data_size == 0) {
37                Location fileLoc(0, path);
38                print_error(&fileLoc, "file is empty");
39            }
40            else {
41                data_size++;
42                rewind(input);
43                buffer =  (char *)malloc(data_size+1);
44                data_size = fread(buffer, 1, data_size, input);
45                buffer[data_size] = 0;
46            }
47        }
48        fclose(input);
49    }
50    return buffer;
51}
52
53inline int max(int i, int j) { return i<j ? j : i; }
54
55void LineQueue::alignInto(LineQueue& dest) {
56    int offset = 0;
57    int len[count];
58
59    for (int i = 0; i<count; ++i) len[i] = strlen(queue[i]);
60
61    while (1) {
62        int max_mark_pos = -1;
63        int mark_pos[count];
64        for (int i = 0; i<count; ++i) {
65            char *line   = queue[i];
66            char *mark   = len[i]>offset ? strchr(line+offset, ALIGN_MARKER) : NULp;
67            mark_pos[i]  = mark ? mark-line : -1;
68            max_mark_pos = max(max_mark_pos, mark_pos[i]);
69        }
70        if (max_mark_pos == -1) break;
71
72        for (int i = 0; i<count; ++i) {
73            if (mark_pos[i] >= 0) {
74                int insert = max_mark_pos-mark_pos[i];
75                aisc_assert(insert >= 0);
76                if (insert >= 0) {
77                    int   new_len  = len[i]+insert;
78                    char *new_line = (char*)malloc(new_len+1);
79
80                    memcpy(new_line, queue[i], mark_pos[i]);
81                    memset(new_line+mark_pos[i], ' ', insert);
82                    strcpy(new_line+max_mark_pos, queue[i]+mark_pos[i]+1);
83
84                    len[i] = new_len;
85                    freeset(queue[i], new_line);
86                }
87            }
88        }
89
90        offset = max_mark_pos;
91    }
92
93    for (int i = 0; i<count; ++i) {
94        dest.add(queue[i]);
95        queue[i] = NULp;
96    }
97    count = 0;
98}
99
100struct queued_line {
101    string line;
102    int    indentation;
103    queued_line(const char *line_, int indent) : line(line_), indentation(indent) { }
104};
105
106typedef list<queued_line> PrintQueue;
107
108class PrintMaybe : virtual Noncopyable {
109    Output&          out;
110    const Location&  started_at;
111    bool             printed_sth;
112    PrintMaybe      *next;
113    PrintQueue       queue;
114
115public:
116    PrintMaybe(PrintMaybe *head, Output& out_, const Location& loc)
117        : out(out_),
118          started_at(loc),
119          printed_sth(false),
120          next(head)
121    {}
122
123    void add(const char *line) {
124        if (printed_sth) {
125            out.write(line);
126        }
127        else {
128            queue.push_back(queued_line(line, out.get_formatter().get_indent()));
129        }
130    }
131    void spool() {
132        aisc_assert(!printed_sth);
133        printed_sth = true;
134        if (!queue.empty()) {
135            Formatter& formatter  = out.get_formatter();
136            int        old_indent = formatter.get_indent();
137            for (PrintQueue::iterator i = queue.begin(); i != queue.end(); ++i) {
138                queued_line& ql = *i;
139                formatter.set_indent(ql.indentation);
140                out.write(ql.line.c_str());
141            }
142            formatter.set_indent(old_indent);
143            queue.clear();
144        }
145    }
146
147    void will_print() {
148        if (next) next->will_print();
149        if (!printed_sth) {
150            spool();
151        }
152    }
153
154    void not_destroyed_error() {
155        print_error(&started_at, "PMSTART without matching PMEND");
156        if (next) next->not_destroyed_error();
157    }
158
159    static void pop(PrintMaybe*& head) {
160        PrintMaybe *next = head->next;
161        head->next       = NULp;
162        delete head;
163        head             = next;
164    }
165};
166
167void Output::setup() {
168    fp    = NULp;
169    id    = NULp;
170    name  = NULp;
171    maybe = NULp;
172
173    have_open_loc = false;
174}
175void Output::cleanup() {
176    close_file();
177    free(id);
178    free(name);
179    if (maybe) {
180        maybe->not_destroyed_error();
181        delete maybe;
182    }
183}
184
185void Output::maybe_start() {
186    maybe = new PrintMaybe(maybe, *this, Interpreter::instance->at()->source);
187}
188int Output::maybe_write(const char *line) {
189    if (!maybe) {
190        print_error(Interpreter::instance->at(), "no PMSTART before PM");
191        return -1;
192    }
193    maybe->add(line);
194    return 0;
195}
196int Output::maybe_end() {
197    if (!maybe) {
198        print_error(Interpreter::instance->at(), "no PMSTART before PMEND");
199        return -1;
200    }
201    PrintMaybe::pop(maybe);
202    return 0;
203}
204
205int Output::write(const char *line) {
206    if (!inUse()) {
207        print_error(Interpreter::instance->at(), "Fatal: attempt to write to unused file");
208        return -1;
209    }
210
211    if (maybe) maybe->will_print();
212
213    int res = formatter.write(line);
214    formatter.flush(fp);
215    return res;
216}
217
218Formatter::Formatter()
219    : tabstop(4),
220      column(0),
221      indent(0),
222      printed_sth(false)
223{
224    set_tabstop(4);
225
226    for (int i = 0; i < 256; i++) {
227        outtab[i] = i;
228    }
229
230    outtab[(unsigned char)'n']  = '\n';
231    outtab[(unsigned char)'t']  = '\t';
232    outtab[(unsigned char)'|']  = ALIGN_MARKER;
233    outtab[(unsigned char)'0']  = 0;
234    outtab[(unsigned char)'1']  = 0;
235    outtab[(unsigned char)'2']  = 0;
236    outtab[(unsigned char)'3']  = 0;
237    outtab[(unsigned char)'4']  = 0;
238    outtab[(unsigned char)'5']  = 0;
239    outtab[(unsigned char)'6']  = 0;
240    outtab[(unsigned char)'7']  = 0;
241    outtab[(unsigned char)'8']  = 0;
242    outtab[(unsigned char)'9']  = 0;
243    outtab[(unsigned char)'\\'] = 0;
244}
245
246int Formatter::write(const char *str) {
247    int         no_nl = 0;
248    const char *p     = str;
249    char        c;
250
251    while ((c = *(p++))) {
252        if (c == '$') {
253            c = *(p++);
254            if (!c)
255                break;
256
257            if (!outtab[(unsigned)(c)]) {
258                if (c == '\\') {
259                    no_nl = 1;
260                }
261                else if (isdigit(c)) {
262                    int pos = tabs[c - '0'];
263                    tab_to_pos(pos);
264                }
265                continue;
266            }
267            else {
268                c = outtab[(unsigned)(c)];
269            }
270        }
271        if (c == '\t') {
272            int pos = ((column/tabstop)+1)*tabstop;
273            tab_to_pos(pos);
274        }
275        else if (c == '\n') {
276            if (no_nl) {
277                no_nl = 0;
278            }
279            else {
280                finish_line();
281            }
282        }
283        else if (c == '@') {
284            if (strncmp(p, "SETSOURCE", 9) == 0) { // skip '@SETSOURCE file, line@'
285                p = strchr(p, '@');
286                if (!p) {
287                    print_error(Interpreter::instance->at(), "expected '@' after '@SETSOURCE' (injected code)");
288                    return 1;
289                }
290                p++;
291            }
292            else {
293                print_char(c);
294            }
295        }
296        else {
297            print_char(c);
298        }
299    }
300    if (!no_nl) {
301        finish_line();
302    }
303    return 0;
304}
305
306bool Interpreter::set_data(const char *dataBlock, int offset_in_line) {
307    parser.set_line_start(dataBlock, offset_in_line);
308    parser.set_source(at()->source); // remove ?
309    data.set_tokens(parser.parseTokenListBlock(dataBlock));
310    return data.get_tokens();
311}
312
313
314int Interpreter::launch(int argc, char ** argv) {
315    int exitcode = EXIT_FAILURE;
316
317    // save CL-arguments as variables (with names like 'argv[0]' ..)
318    {
319        for (int i=0; i<argc; i++) {
320            write_var(formatted("argv[%i]", i), argv[i]);
321        }
322        write_var("argc", formatted("%i", argc));
323    }
324
325    {
326        char *buf = read_aisc_file(argv[1], NULp);
327        if (buf) {
328            prg = parser.parse_program(buf, argv[1]);
329            free(buf);
330        }
331    }
332
333    if (!prg) {
334        fputs("Nothing to execute\n", stderr);
335    }
336    else {
337        if (compile_program()) {
338            fprintf(stderr, "Compilation of '%s' failed\n", argv[1]);
339        }
340        else {
341            if (run_program()) {
342                if (!Location::get_error_count()) {
343                    print_error(at(), "AISC compiler bailed out w/o error");
344                }
345                fputs("AISC reports errors\n", stderr);
346                for (int i = 0; i < OPENFILES; i++) output[i].close_and_unlink();
347                fflush(stdout);
348            }
349            else {
350                aisc_assert(!Location::get_error_count());
351                exitcode = EXIT_SUCCESS;
352            }
353        }
354    }
355
356    return exitcode;
357}
358
359int main(int argc, char ** argv) {
360    int exitcode = EXIT_FAILURE;
361
362    if (argc < 2) {
363        fprintf(stderr, "AISC - ARB integrated source compiler\n");
364        fprintf(stderr, "Usage: aisc [fileToCompile]+\n");
365        fprintf(stderr, "Error: missing file name\n");
366    }
367    else {
368        try {
369            exitcode = Interpreter().launch(argc, argv);
370        }
371        catch (const char *err) {
372            fprintf(stderr, "\nAISC: exception: %s [terminating]\n", err);
373            exitcode = EXIT_FAILURE;
374        }
375        catch (...) {
376            fprintf(stderr, "\nAISC: unknown exception [terminating]\n");
377            exitcode = EXIT_FAILURE;
378        }
379    }
380    return exitcode;
381}
382
383
Note: See TracBrowser for help on using the repository browser.