aboutsummaryrefslogtreecommitdiff
path: root/print.c
blob: abdb14937bb17a41832667f1b8576354b60e15c1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#include "print.h"
#include "errloc.h"
#include "fn.h"
#include "lit.h"
#include "parse.h"
#include "prv.h"
#include "stmt.h"
#include "storage.h"
#include "type.h"
#include <stdlib.h>
#include <string.h>

static int entry(const struct lex *l, const struct tk *tk, struct print *pr,
    struct prv *p)
{
    size_t n = pr->nentries + 1;
    struct prientry *entries;
    const struct stentry *stentry = NULL;
    const struct fn *fn = fn_cur(p);
    const struct lit *lit = NULL;

    if (tk->type == ID)
    {
        const struct type *t = NULL;

        if ((t = type_find(fn, tk->s)))
        {
            if (t->type != C)
            {
                errloc(tk, "type \"%s\" not a constant", tk->s);
                return -1;
            }
            else if (!(lit = lit_push(t->tk, p)))
                return -1;
        }
        else if (!(stentry = fn_var(fn, tk)))
        {
            errloc(tk, "undefined reference to \"%s\"", tk->s);
            return -1;
        }
    }
    else if (tk->type == LIT && !(lit = lit_push(tk, p)))
        return -1;

    if (!(entries = realloc(pr->entries, n * sizeof *entries)))
    {
        perror("realloc(3)");
        return -1;
    }

    pr->entries = entries;
    pr->entries[pr->nentries++] = (struct prientry)
    {
        .tk = tk,
        .lit = lit,
        .entry = stentry
    };

    return 0;
}

void print_free(struct print *pr)
{
    free(pr->entries);
}

int print(const struct lex *l, struct prv *p,
    int (*fn)(const struct lex *, const struct prv *, const struct print *))
{
    const struct tk *tk = p->stk + 1;
    struct print pr = {0};
    struct pos *pos = &p->pos[p->i];
    int eof;

    if (lex_eof(l, tk))
    {
        errloc(tk - 1, "incomplete %s statement", p->stk->s);
        return -1;
    }

    for (;;)
        if (entry(l, tk, &pr, p))
            goto failure;
        else if ((eof = lex_eof(l, ++tk)) || kw(tk->s))
            break;

    if (eof || strcmp(tk->s, "etc"))
        pr.println = 1;
    else if (!eof)
        tk++;

    if (fn(l, p, &pr))
        goto failure;

    pos->seq = pos->stseq = stmts;
    pos->step = stmts->steps;
    p->stk = tk;
    return 1;

failure:
    print_free(&pr);
    return -1;
}