-
Notifications
You must be signed in to change notification settings - Fork 0
/
parser.c
168 lines (138 loc) · 4.3 KB
/
parser.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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#include "ast.h"
#include "parser.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
static void so_parse_call(so_parser *);
static void so_parse_load(so_parser *);
static so_expr *so_parser_parse_simple_expression(so_parser *);
static so_token so_parser_advance(so_parser *p) {
p->current = so_lexer_next_token(&p->lexer);
return p->current;
}
static int so_parser_expect(so_parser *p, so_token_type tt) {
if (p->current.type != tt) {
char buffer[20] = {0};
so_token_type_to_string(tt, buffer, sizeof(buffer));
fprintf(stderr, "warning: expected a token of type: %s\n", buffer);
return 0;
}
return 1;
}
static void add_command(so_parser *p, so_expr *e) {
if (p->ncommands >= MAX_COMMANDS) {
fprintf(stderr, "warning: maximum number of commands reached\n");
return;
}
p->commands[p->ncommands++] = e;
}
void so_parser_init(so_parser *p, const char *source) {
p->source = source;
p->ncommands = 0;
so_lexer_init(&p->lexer, source);
}
void so_parser_deinit(so_parser *p) {
p->source = NULL;
p->ncommands = 0;
memset(p->commands, 0, MAX_COMMANDS * sizeof(so_expr *));
so_lexer_deinit(&p->lexer);
}
void so_parser_parse(so_parser *p) {
while (so_parser_advance(p).type != SO_TT_EOF) {
switch (p->current.type) {
case SO_TT_USE:
so_parse_load(p);
break;
case SO_TT_CALL:
so_parse_call(p);
break;
case SO_TT_EOL: // Happens on an empty line
so_token_deinit(&p->current);
break;
case SO_TT_EOF: // Happens at end of input
so_token_deinit(&p->current);
return;
default:
fprintf(stderr, "warning: invalid start of expression, expected use or call: %s\n", p->current.lexeme);
so_token_deinit(&p->current);
}
}
so_token_deinit(&p->current);
}
void so_parse_call(so_parser *p) {
if (!so_parser_expect(p, SO_TT_CALL)) {
so_token_deinit(&p->current);
return;
}
so_token_deinit(&p->current);
so_parser_advance(p);
if (!so_parser_expect(p, SO_TT_BARE)) {
so_token_deinit(&p->current);
return;
}
so_token name = p->current;
so_expr *args[MAX_CALL_ARGS];
int nargs = 0;
while (so_parser_advance(p).type != SO_TT_EOF && p->current.type != SO_TT_EOL && nargs < MAX_CALL_ARGS) {
so_expr *e = so_parser_parse_simple_expression(p);
if (e == NULL) {
char type[10] = {0};
so_token_type_to_string(p->current.type, type, sizeof(type));
fprintf(
stderr,
"warning: expected either a string or a number, but got %s\n",
type);
so_token_deinit(&p->current);
continue;
}
args[nargs++] = e;
}
if (!so_parser_expect(p, SO_TT_EOL)) {
fprintf(stderr, "warning: expected an end of line\n");
so_token_deinit(&p->current);
return;
}
so_expr *e = create_call_node(name.lexeme, nargs, args);
add_command(p, e);
so_token_deinit(&p->current);
so_token_deinit(&name);
}
void so_parse_load(so_parser *p) {
if (!so_parser_expect(p, SO_TT_USE)) {
so_token_deinit(&p->current);
return;
}
so_token use = p->current;
so_parser_advance(p);
if (!so_parser_expect(p, SO_TT_STRING)) {
so_token_deinit(&use);
so_token_deinit(&p->current);
return;
}
so_token name = p->current;
so_parser_advance(p);
if (!so_parser_expect(p, SO_TT_EOL)) {
so_token_deinit(&use);
so_token_deinit(&name);
so_token_deinit(&p->current);
return;
}
so_expr *e = create_load_node(name.lexeme);
add_command(p, e);
so_token_deinit(&use);
so_token_deinit(&name);
so_token_deinit(&p->current);
}
so_expr *so_parser_parse_simple_expression(so_parser *p) {
so_expr *e = NULL;
if (p->current.type == SO_TT_STRING) {
e = create_string_node(p->current.lexeme);
so_token_deinit(&p->current);
}
if (p->current.type == SO_TT_INTEGER) {
int n = atoi(p->current.lexeme);
e = create_number_node(n);
so_token_deinit(&p->current);
}
return e;
}