aboutsummaryrefslogtreecommitdiff
path: root/src/prc1/end.c
blob: b9ad7903e02f30b1ed354213e0a3deecf9f0dcea (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
#include "end.h"
#include "errloc.h"
#include "fn.h"
#include "stmt.h"
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>

void end_free(struct end *e)
{
}

int end_cgen(const struct end *e, struct cgen *c)
{
    const struct stmt *s = &c->fn->stmts[e->block_i];

    if (!s->end)
    {
        fprintf(stderr, "%s: unreachable\n", __func__);
        return -1;
    }
    else if (s->end(s, c))
        return -1;

    printf("@__end%zu\n", e->block_i);
    return 0;
}

int end(const struct lex *l, struct prv *p)
{
    struct pos *pos = &p->pos[p->i];
    struct fn *fn = fn_cur(p);
    size_t nst = fn->nstmts + 1, *bl, bl_i;
    struct stmt *s;

    if (!fn->nblocks)
    {
        errloc(p->stk, "unexpected \"end\" statement");
        return -1;
    }

    bl_i = fn->blocks[fn->nblocks - 1];

    if (fn->nblocks > 1)
    {
        if (!(bl = realloc(fn->blocks, (fn->nblocks - 1) * sizeof *bl)))
        {
            perror("realloc(3)");
            return -1;
        }

        fn->blocks = bl;
    }
    else
    {
        free(fn->blocks);
        fn->blocks = NULL;
    }

    fn->nblocks--;

    if (!(s = realloc(fn->stmts, nst * sizeof *s)))
    {
        perror("realloc(3)");
        return -1;
    }

    s[fn->nstmts++] = (struct stmt)
    {
        .type = END,
        .u.end.block_i = bl_i
    };

    fn->stmts = s;
    pos->seq = pos->stseq = stmts;
    pos->step = stmts->steps;
    p->stk = p->tk;
    fprintf(stderr, "\t\tadding end statement, block index %zu\n", bl_i);
    return 1;
}