summary refs log tree commit diff
path: root/src/operation.c
blob: c56e381394e90e2864616f0baca4202ef8b3c39c (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
127
128
129
130
131
132
133
#include "operation.h"
#include "types.h"

#include <cvector/cvector.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>

#include "cccl.h"
#include "utils.h"


static cccl *pc;
static bool is_comment;
static i32  current;

static const s8 *const name_allowed             = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
static const s8 *const all_allowed              = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_{}[]()?;@=!&$%<>^+-*~#:/ \n\t";
static const s8 *const skippable                = " \t\n";
static const s8 *const open_brackets            = "[({?";
static const s8 *const close_brackets           = "])};";

static void check_symbol(void)
{
    if (!strchr(all_allowed, pc->code[pc->ep]))
        die(1, "illegal character (%u at %d)", pc->code[pc->ep], pc->ep);
}

static s8 read_operand(bool allow_underscore)
{
    i32 start = pc->ep;
    for (++pc->ep; pc->ep < pc->size; ++pc->ep)
    {
        check_symbol();
        if (strchr(skippable, pc->code[pc->ep]))
            continue;
        if (!strchr(allow_underscore ? name_allowed : name_allowed + 1, pc->code[pc->ep]))
            die(
                1, "invalid operand name (%c at %d for %c at %d)",
                pc->code[pc->ep], pc->ep,
                pc->code[start], start
            );
        return pc->code[pc->ep];
    }
    die(
        1, "no operand (for %c at %d)",
        pc->code[start], start
    );
}

static void require_stack_size(u32 size)
{
    if (cvector_size(pc->stack) < size)
        die(1, "stack size is %d, but %d is required (%c at %d)", cvector_size(pc->stack), size, pc->code[current], current);
}

static void op_noth(void) {}

static void op_comment(void)
{
    is_comment = !is_comment;
}

static void op_pushzero(void)
{
    cvector_push_back(pc->stack, 0);
}

static void op_increment(void)
{
    require_stack_size(1);
    ++*cvector_back(pc->stack);
}

static void op_decrement(void)
{
    require_stack_size(1);
    --*cvector_back(pc->stack);
}

static void op_add(void)
{
    require_stack_size(2);
    *(cvector_back(pc->stack) - 1) += *cvector_back(pc->stack);
    cvector_pop_back(pc->stack);
}

static void op_sub(void)
{
    require_stack_size(2);
    *(cvector_back(pc->stack) - 1) -= *cvector_back(pc->stack);
    cvector_pop_back(pc->stack);
}

static void op_reverse(void)
{
    s8 operand = read_operand(true);
    i16 *to_reverse = NULL;
    i32 size;

    if (operand == '_')
        size = cvector_size(pc->stack);
}

void cccl_operation_init(cccl *pcp)
{
    pc = pcp;
    is_comment = false;
    current = 0;
}

cccl_operation cccl_select_operation(void)
{
    if (is_comment && pc->code[pc->ep] == '\n')
        return op_comment;
    if (is_comment)
        return op_noth;

    current = pc->ep;
    check_symbol();

    switch (pc->code[pc->ep])
    {
    case ' ':  /* FALLTHROUGH */
    case '\t': /* FALLTHROUGH */
    case ';':  return op_noth;
    case '/':  return op_comment;
    case '^':  return op_pushzero;
    case '+':  return op_increment;
    case '-':  return op_decrement;
    default:   die(1, "You shouldn't be there!");
    }
}