aboutsummaryrefslogtreecommitdiff
path: root/parts/table.h
blob: ff4601febd87a9d8a5b1aa6ca46553396aaf5575 (plain)
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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#ifndef TABLE_H
#define TABLE_H

#include <stddef.h> // size_t
#include "util/util.h"

#define ACTION_TYPE(X) \
    X(ACTION_NOT_SET)  \
    X(ACTION_SHIFT)    \
    X(ACTION_GOTO)     \
    X(ACTION_REDUCE)   \
    X(ACTION_ACCEPT)

const char * const action_type_to_char[] = {
    ACTION_TYPE(X_TO_STR)
};

extern struct action {
    enum action_type { ACTION_TYPE(X_TO_ENUM) } type;
    size_t arg;
} **table;

extern size_t table_states;

extern int (*table_fill)(); // non-zero on fail
extern void (*table_free)();

void table_print();
void table_print_cstyle();
int table_insert(size_t state, symbol sym, struct action a); // should it be here??

#include "symbol.h"

void table_print()
{
    printf("    ");
    for(size_t sym = 0; sym < total_symbols; sym++) printf("%2zu  ", sym);
    printf("\n");

    char action_to_char[] = {[ACTION_SHIFT] = 's', [ACTION_REDUCE] = 'r', [ACTION_GOTO] = 'g'};
    for(size_t i = 0; i < table_states; i++) {
        printf("%2zu  ", i);
        for(size_t sym = 0; sym < total_symbols; sym++)
            if(table[i][sym].type == ACTION_ACCEPT) printf(" a  ");
            else if(table[i][sym].type) printf("%c%-2zu ", action_to_char[table[i][sym].type], table[i][sym].arg);
            else printf("    ");
        printf("\n");
    }


}

void table_print_cstyle()
{
    for(size_t i = 0; i < table_states; i++) {
        printf("(struct action[]){");
        for(size_t sym = 0; sym < total_symbols; sym++)
            printf("{%d, %zu},", table[i][sym].type, table[i][sym].arg);
        printf("},\n");
    }
}

#include "grammar.h"
int table_insert(size_t state, symbol sym, struct action a)
{
    struct action *tbl_a = &table[state][sym];
    struct action *new_a = &a;

    if(tbl_a->type == new_a->type && tbl_a->arg == new_a->arg) return 0;
    if(tbl_a->type == ACTION_NOT_SET) {
        *tbl_a = *new_a;
        return 0;
    }

    int r = 0, report = 0, set_tbl_a = 0,
    reduce_reduce = 0, shift_reduce = 0;
    struct action *shift_a;

    if((tbl_a->type == ACTION_REDUCE && new_a->type == ACTION_REDUCE))       reduce_reduce = 1;
    else if((tbl_a->type == ACTION_REDUCE && new_a->type == ACTION_SHIFT))   { shift_reduce = 1;
        shift_a = new_a;
    } else if((tbl_a->type == ACTION_SHIFT && new_a->type == ACTION_REDUCE)) { shift_reduce = 1;
        shift_a = tbl_a;
    }

#define prec_num(a)  PRECEDENCE_NUM(grammar[(a)->arg].precedence)
#define prec_flag(a) PRECEDENCE_FLAG(grammar[(a)->arg].precedence)

    if(reduce_reduce || shift_reduce) {
        if(prec_num(tbl_a) == 0 || prec_num(new_a) == 0) report = 1;

        if(prec_num(tbl_a) > prec_num(new_a))      set_tbl_a = 0;
        else if(prec_num(tbl_a) < prec_num(new_a)) set_tbl_a = 1;
        else if(reduce_reduce) {
            report = 1;
            if(new_a->arg > tbl_a->arg) set_tbl_a = 1;
        } else {
            if(prec_flag(tbl_a) == PRECEDENCE_NO_ASSOC && tbl_a->arg == new_a->arg) {
                report = 1; r = 2;
            } else if(prec_flag(shift_a) == PRECEDENCE_LEFT_ASSOC) {
                if(shift_a == tbl_a) set_tbl_a = 1; // favor reduce
            }else {
                if(shift_a == new_a) set_tbl_a = 1; // favor shift
            }
        }
    } else {
        r = 1; report = 1;
    }

    if(report) {
        struct action *a0 = (set_tbl_a) ? new_a: tbl_a;
        struct action *a1 = (set_tbl_a) ? tbl_a: new_a;

        fprintf(stderr, "REPORT: table collission on state '%zu' sym '%d'\n", state, sym);
        fprintf(stderr, "\t%s resolve: {%s %zu} %s {%s %zu}\n",
                (r == 0) ? "SUCCESSFULLY" : "COULD NOT",
                action_type_to_char[a0->type], a0->arg,
                (r == 0) ? "over" : "vs",
                action_type_to_char[a1->type], a1->arg);
    }

    if(!r && set_tbl_a) *tbl_a = *new_a;
    return r;
}

#endif