-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathparser.h
163 lines (139 loc) · 4.19 KB
/
parser.h
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
#ifndef PARSER_H
#define PARSER_H
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <stdbool.h>
#include <ctype.h>
#include "util.h"
#include "types.h"
LispExpr* make_symbol(char* val) {
LispExpr* e = malloc(sizeof(LispExpr));
e->type = SYMBOL;
e->data.symbol = val;
return e;
}
LispExpr* make_number(float val) {
LispExpr* e = malloc(sizeof(LispExpr));
e->type = NUMBER;
e->data.number = val;
return e;
}
LispExpr* make_list() {
LispExpr* e = malloc(sizeof(LispExpr));
e->type = LIST;
e->data.list = malloc(sizeof(LispList));
LIST_INIT(e->data.list, struct LispExpr*);
return e;
}
LispExpr* make_cons(LispExpr* first, LispExpr* second) {
LispExpr* e = malloc(sizeof(LispExpr));
e->type = CONS;
e->data.cons.first = first;
e->data.cons.second = second;
return e;
}
LispExpr* make_func(char* name, CharList* params, LispExpr* body) {
LispExpr* e = malloc(sizeof(LispExpr));
e->type = FUNCTION;
e->data.func = malloc(sizeof(LispFunc));
e->data.func->name = name;
e->data.func->params = params;
e->data.func->body = body;
return e;
}
CharList* tokenize(char* inp) {
CharList* tokens = malloc(sizeof(CharList));
LIST_INIT(tokens, char*);
while (*inp != '\0') {
switch (*inp) {
case '(':
LIST_APPEND(tokens, char*, strdup("("));
inp++;
break;
case ')':
LIST_APPEND(tokens, char*, strdup(")"));
inp++;
break;
case ' ':
case '\t':
case '\n':
case '\r':
inp++;
break;
default: {
// Collect the token
int len = 0;
char buf[1024]; // Safe buffer for token collection
// Collect characters until we hit a delimiter
while (*inp && !strchr("() \t\n\r", *inp)) {
buf[len++] = *inp++;
}
buf[len] = '\0';
// Check if it's a number
if (isdigit(buf[0]) || (buf[0] == '-' && isdigit(buf[1]))) {
char* endptr;
strtof(buf, &endptr);
if (*endptr == '\0') { // Valid number
LIST_APPEND(tokens, char*, strdup(buf));
continue;
}
}
// Not a number, treat as symbol
LIST_APPEND(tokens, char*, strdup(buf));
break;
}
}
}
return tokens;
}
static LispExpr* parse_expr(CharList* tokens, int* idx);
LispExpr* parse(CharList* tokens) {
int idx = 0;
return parse_expr(tokens, &idx);
}
static LispExpr* parse_expr(CharList* tokens, int* idx) {
for (; *idx < tokens->size; (*idx)++) {
char* tok = tokens->data[*idx];
if (strcmp(tok, "(") == 0) {
if (*idx + 1 < tokens->size && strcmp(tokens->data[*idx + 1], "define") == 0) {
(*idx) += 2; // Skip past '(' and 'define'
if (strcmp(tokens->data[*idx], "(") == 0) {
(*idx)++; // Skip past the opening paren of function name and params
char* fname = tokens->data[(*idx)++]; // Get function name
CharList* params = malloc(sizeof(CharList));
LIST_INIT(params, char*);
while (*idx < tokens->size && strcmp(tokens->data[*idx], ")") != 0) {
LIST_APPEND(params, char*, tokens->data[(*idx)++]);
}
(*idx)++; // Skip past closing paren of params
LispExpr* body = parse_expr(tokens, idx);
(*idx)++; // Skip past closing paren of define
return make_func(fname, params, body);
}
} else {
LispExpr* e = make_list();
LispList* list = e->data.list;
for ((*idx)++; *idx < tokens->size; (*idx)++) {
LispExpr* tmp = parse_expr(tokens, idx);
if (!tmp) break;
LIST_APPEND(list, struct LispExpr*, tmp);
}
return e;
}
}
else if (strcmp(tok, ")") == 0) return NULL;
else {
// Modified number checking to handle negative numbers
char* endptr;
float num = strtof(tok, &endptr);
if (*endptr == '\0' || (tok[0] == '-' && isdigit(tok[1]))) {
return make_number(num);
}
return make_symbol(tok);
}
}
return NULL;
}
#endif