source: branches/profile/AISC/aisc.c

Last change on this file was 8823, checked in by westram, 12 years ago
  • add realloc_unleaked() - does not leak if realloc fails (just sets ptr to NULL)
  • AISC
    • replaced problematic realloc's and throw if realloc fails
    • add exception handling to main
    • check Interpreter was instanciated before accessing it (crashed during early throw)
    • cppcheck-suppress two acceptable leaks
  • 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 = 0;
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) : NULL;
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] = NULL;
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    ~PrintMaybe() {
124    }
125
126    void add(const char *line) {
127        if (printed_sth) {
128            out.write(line);
129        }
130        else {
131            queue.push_back(queued_line(line, out.get_formatter().get_indent()));
132        }
133    }
134    void spool() {
135        aisc_assert(!printed_sth);
136        printed_sth = true;
137        if (!queue.empty()) {
138            Formatter& formatter  = out.get_formatter();
139            int        old_indent = formatter.get_indent();
140            for (PrintQueue::iterator i = queue.begin(); i != queue.end(); ++i) {
141                queued_line& ql = *i;
142                formatter.set_indent(ql.indentation);
143                out.write(ql.line.c_str());
144            }
145            formatter.set_indent(old_indent);
146            queue.clear();
147        }
148    }
149
150    void will_print() {
151        if (next) next->will_print();
152        if (!printed_sth) {
153            spool();
154        }
155    }
156
157    void not_destroyed_error() {
158        print_error(&started_at, "PMSTART without matching PMEND");
159        if (next) next->not_destroyed_error();
160    }
161
162    static void pop(PrintMaybe*& head) {
163        PrintMaybe *next = head->next;
164        head->next       = NULL;
165        delete head;
166        head             = next;
167    }
168};
169
170void Output::setup() {
171    fp    = NULL;
172    id    = NULL;
173    name  = NULL;
174    maybe = NULL;
175
176    have_open_loc = false;
177}
178void Output::cleanup() {
179    close_file();
180    free(id);
181    free(name);
182    if (maybe) {
183        maybe->not_destroyed_error();
184        delete maybe;
185    }
186}
187
188void Output::maybe_start() {
189    maybe = new PrintMaybe(maybe, *this, Interpreter::instance->at()->source);
190}
191int Output::maybe_write(const char *line) {
192    if (!maybe) {
193        print_error(Interpreter::instance->at(), "no PMSTART before PM");
194        return -1;
195    }
196    maybe->add(line);
197    return 0;
198}
199int Output::maybe_end() {
200    if (!maybe) {
201        print_error(Interpreter::instance->at(), "no PMSTART before PMEND");
202        return -1;
203    }
204    PrintMaybe::pop(maybe);
205    return 0;
206}
207
208int Output::write(const char *line) {
209    if (!inUse()) {
210        print_error(Interpreter::instance->at(), "Fatal: attempt to write to unused file");
211        return -1;
212    }
213
214    if (maybe) maybe->will_print();
215
216    int res = formatter.write(line);
217    formatter.flush(fp);
218    return res;
219}
220
221Formatter::Formatter()
222    : tabstop(4),
223      column(0),
224      indent(0),
225      printed_sth(false)
226{
227    set_tabstop(4);
228
229    for (int i = 0; i < 256; i++) {
230        outtab[i] = i;
231    }
232
233    outtab[(unsigned char)'n']  = '\n';
234    outtab[(unsigned char)'t']  = '\t';
235    outtab[(unsigned char)'|']  = ALIGN_MARKER;
236    outtab[(unsigned char)'0']  = 0;
237    outtab[(unsigned char)'1']  = 0;
238    outtab[(unsigned char)'2']  = 0;
239    outtab[(unsigned char)'3']  = 0;
240    outtab[(unsigned char)'4']  = 0;
241    outtab[(unsigned char)'5']  = 0;
242    outtab[(unsigned char)'6']  = 0;
243    outtab[(unsigned char)'7']  = 0;
244    outtab[(unsigned char)'8']  = 0;
245    outtab[(unsigned char)'9']  = 0;
246    outtab[(unsigned char)'\\'] = 0;
247}
248
249int Formatter::write(const char *str) {
250    int         no_nl = 0;
251    const char *p     = str;
252    char        c;
253
254    while ((c = *(p++))) {
255        if (c == '$') {
256            c = *(p++);
257            if (!c)
258                break;
259
260            if (!outtab[(unsigned)(c)]) {
261                if (c == '\\') {
262                    no_nl = 1;
263                }
264                else if (isdigit(c)) {
265                    int pos = tabs[c - '0'];
266                    tab_to_pos(pos);
267                }
268                continue;
269            }
270            else {
271                c = outtab[(unsigned)(c)];
272            }
273        }
274        if (c == '\t') {
275            int pos = ((column/tabstop)+1)*tabstop;
276            tab_to_pos(pos);
277        }
278        else if (c == '\n') {
279            if (no_nl) {
280                no_nl = 0;
281            }
282            else {
283                finish_line();
284            }
285        }
286        else if (c == '@') {
287            if (strncmp(p, "SETSOURCE", 9) == 0) { // skip '@SETSOURCE file, line@'
288                p = strchr(p, '@');
289                if (!p) {
290                    print_error(Interpreter::instance->at(), "expected '@' after '@SETSOURCE' (injected code)");
291                    return 1;
292                }
293                p++;
294            }
295            else {
296                print_char(c);
297            }
298        }
299        else {
300            print_char(c);
301        }
302    }
303    if (!no_nl) {
304        finish_line();
305    }
306    return 0;
307}
308
309bool Interpreter::set_data(const char *dataBlock, int offset_in_line) {
310    parser.set_line_start(dataBlock, offset_in_line);
311    parser.set_source(at()->source); // remove ?
312    data.set_tokens(parser.parseTokenListBlock(dataBlock));
313    return data.get_tokens();
314}
315
316
317int Interpreter::launch(int argc, char ** argv) {
318    int exitcode = EXIT_FAILURE;
319
320    // save CL-arguments as variables (with names like 'argv[0]' ..)
321    {
322        for (int i=0; i<argc; i++) {
323            write_var(formatted("argv[%i]", i), argv[i]);
324        }
325        write_var("argc", formatted("%i", argc));
326    }
327
328    {
329        char *buf = read_aisc_file(argv[1], NULL);
330        if (buf) {
331            prg = parser.parse_program(buf, argv[1]);
332            free(buf);
333        }
334    }
335   
336    if (!prg) {
337        fputs("Nothing to execute\n", stderr);
338    }
339    else {
340        if (compile_program()) {
341            fprintf(stderr, "Compilation of '%s' failed\n", argv[1]);
342        }
343        else {
344            if (run_program()) {
345                if (!Location::get_error_count()) {
346                    print_error(at(), "AISC compiler bailed out w/o error");
347                }
348                fputs("AISC reports errors\n", stderr);
349                for (int i = 0; i < OPENFILES; i++) output[i].close_and_unlink();
350                fflush(stdout);
351            }
352            else {
353                aisc_assert(!Location::get_error_count());
354                exitcode = EXIT_SUCCESS;
355            }
356        }
357    }
358
359    return exitcode;
360}
361
362int main(int argc, char ** argv) {
363    int exitcode = EXIT_FAILURE;
364
365    if (argc < 2) {
366        fprintf(stderr, "AISC - ARB integrated source compiler\n");
367        fprintf(stderr, "Usage: aisc [fileToCompile]+\n");
368        fprintf(stderr, "Error: missing file name\n");
369    }
370    else {
371        try {
372            exitcode = Interpreter().launch(argc, argv);
373        }
374        catch (const char *err) {
375            fprintf(stderr, "\nAISC: exception: %s [terminating]\n", err);
376            exitcode = EXIT_FAILURE;
377        }
378        catch (...) {
379            fprintf(stderr, "\nAISC: unknown exception [terminating]\n");
380            exitcode = EXIT_FAILURE;
381        }
382    }
383    return exitcode;
384}
385
386
Note: See TracBrowser for help on using the repository browser.