-
Notifications
You must be signed in to change notification settings - Fork 1
/
parse.c
138 lines (125 loc) · 2.9 KB
/
parse.c
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
134
135
136
137
138
#include "parse.h"
static struct Token *in;
void
error_expected(char *expect) {
fprintf(stderr, "Parse error: Expected %s", expect);
exit(EXIT_FAILURE);
}
// Determines whether the next token is of the requested type
// If so, the token pointer is advanced
// Else throw an error and exit program
static bool
expect(enum TokenType t) {
if(in == NULL) {
fprintf(stderr, "Reached end of input before expected %s\n", tok_string[t]);
exit(EXIT_FAILURE);
}
if(in->type == t) {
in++;
return true;
} else {
//TODO encode column num in tokens
fprintf(stderr,"Expected %s, found %s instead\n", tok_string[t], tok_string[in->type]);
exit(EXIT_FAILURE);
}
}
// Consumes the next token if it is of the requested type and returns true
static bool
accept(enum TokenType t) {
if(in->type == t) {
in++;
return true;
}
return false;
}
/*
* Each nonterminal is represented by a function here. Terminals are
* represented by token(TokenType).
* See grammar.ebnf for a mostly-formal grammar.
*/
static Block *factor();
static Block *term();
static Block *expression();
static Block *
value() {
Block *block = NULL;
if(in->type == NUM || in->type == VAR) {
int height = 1;
int width = mbwidth(in->name);
char *lines[1];
lines[0] = in->name;
block = new_block(width, height, lines);
in++;
}
return block;
}
static Block *
factor() {
Block *block = NULL;
if(accept(OPAREN)) {
block = expression();
expect(CLOPAREN);
block = concath(oparen(block->height), block);
block = concath(block, cloparen(block->height));
} else if(accept(OBRACKET)) {
block = expression();
expect(CLOBRACKET);
block = concath(obracket(block->height), block);
block = concath(block, clobracket(block->height));
} else if(accept(OBRACE)) {
block = expression();
expect(CLOBRACE);
block = concath(obrace(block->height), block);
block = concath(block, clobrace(block->height));
} else {
block = value();
}
return block;
}
static Block *
fraction() {
Block *block;
block = factor();
if(block && accept(DIV)) {
Block *block2 = fraction();
if(block2) {
block = concatv(block, stretch1h(max(block->width, block2->width),"⎯"));
block = concatv(block, block2);
}
}
return block;
}
static Block *
term() {
Block *block;
block = fraction();
if(accept(PROD)) {
block = concath(block, single("⋅"));
block = concath(block, term());
}
return block;
}
static Block *
expression() {
Block *block;
block = term();
if(accept(ADD)) {
block = concath(block, single("+"));
block = concath(block, expression());
} else if(accept(SUB)) {
block = concath(block, single("-"));
block = concath(block, expression());
}
return block;
}
Block *
parse(struct Token *input)
{
in = input;
Block *block = expression();
if(in->type != EOL) {
fprintf(stderr, "Trailing characters; Possible missing operator before %s\n", in->name? in->name : tok_string[in->type]);
exit(EXIT_FAILURE);
}
return block;
}