expr.c (6391B)
1 #include "../parser.h" 2 #include "../utils.h" 3 4 #include <stdio.h> 5 #include <string.h> 6 #include <stdbool.h> 7 #include <assert.h> 8 9 Node* 10 parse_func_call(Parser* par) 11 { 12 Token tok = expect(par, TOKEN_IDENT); 13 Span callee = { .start = tok.start, .end = tok.end }; 14 Node* ident = make_ident_node(callee); 15 16 const char* name = span_str(par->src, ident->data.ident.name, (char[IDENTSZ]) { 0 }); 17 printf("parse_func_call: %s\n", name); 18 19 expect(par, TOKEN_LPAREN); 20 21 Node* call = (Node*)calloc(1, sizeof(Node)); 22 if (call == NULL) panic("parse_func_call: alloc failed"); 23 24 // start parse arguments 25 if (peek(par).type != TOKEN_RPAREN) { 26 call->data.call_expr.args = (Node**)calloc(4, sizeof(Node*)); 27 if (call->data.call_expr.args == NULL) panic("parse_func_call: args: could not alloc"); 28 call->data.call_expr.cap = 4; 29 call->data.call_expr.len = 0; 30 31 for (;;) { 32 Node* arg = parse_expression(par); 33 34 if (call->data.call_expr.len == call->data.call_expr.cap) { 35 call->data.call_expr.cap *= 2; 36 call->data.call_expr.args 37 = (Node**)realloc(call->data.call_expr.args, call->data.call_expr.cap * sizeof(Node*)); 38 } 39 call->data.call_expr.args[call->data.call_expr.len++] = arg; 40 41 if (!match(par, TOKEN_COMMA)) break; // found `)` instead of `,` 42 } 43 } 44 // ends parse arguments 45 46 expect(par, TOKEN_RPAREN); 47 48 call->type = NODE_CALL_EXPR; 49 call->scope = NULL; 50 call->data.call_expr.callee = ident; 51 return call; 52 } 53 54 Node* 55 parse_number(Parser* par) 56 { 57 Token tok = consume(par); 58 assert(tok.type == TOKEN_INT_LITERAL || tok.type == TOKEN_FLOAT_LITERAL); 59 60 size_t len = tok.end - tok.start; 61 char buf[len + 1]; // strtod needs a \0 terminated string 62 for (size_t i = 0; i < len; i++) 63 buf[i] = par->src[tok.start + i]; 64 buf[len] = '\0'; 65 double value = strtod(buf, NULL); 66 67 Node* num_node = (Node*)calloc(1, sizeof(Node)); 68 if (num_node == NULL) panic("parse_number: alloc failed"); 69 num_node->type = tok.type == TOKEN_INT_LITERAL ? NODE_INT_LITERAL : NODE_FLOAT_LITERAL; 70 num_node->scope = NULL; 71 num_node->data.number.value = value; 72 return num_node; 73 } 74 75 Node* 76 parse_ident(Parser* par) 77 { 78 Token tok = consume(par); 79 assert(tok.type == TOKEN_IDENT); 80 Node* ident_node = (Node*)calloc(1, sizeof(Node)); 81 if (ident_node == NULL) panic("parse_ident: alloc failed"); 82 ident_node->type = NODE_IDENT; 83 ident_node->scope = NULL; 84 ident_node->data.ident.name = (Span) { .start = tok.start, .end = tok.end }; 85 86 // const char* name = span_str( 87 // par->src, (Span) { .start = tok.start, .end = tok.end }, (char[IDENTSZ]) { 0 }); 88 // printf("parse_ident: %s\n", name); 89 90 return ident_node; 91 } 92 93 NodeVec 94 parse_func_arguments(Parser* par) 95 { 96 NodeVec v = { 0 }; 97 if (peek(par).type == TOKEN_RPAREN) return v; // found `)` no arguments 98 99 v.cap = 4; 100 v.items = (Node**)calloc(v.cap, sizeof(Node*)); 101 if (v.items == NULL) panic("parse_func_arguments: could not alloc"); 102 103 for (;;) { 104 Node* arg = parse_expression(par); 105 106 if (v.len == v.cap) { 107 v.cap *= 2; 108 v.items = (Node**)realloc(v.items, v.cap * sizeof(Node*)); 109 } 110 111 v.items[v.len++] = arg; 112 113 if (!match(par, TOKEN_COMMA)) break; // found `)` instead of `,` 114 } 115 return v; 116 } 117 118 Node* 119 parse_postfix(Parser* par) 120 { 121 Node* node = parse_primary(par); 122 123 for (;;) { 124 if (match(par, TOKEN_PLUSPLUS)) { 125 node = make_postfix_node(OPER_POSTINC, node); 126 } else if (match(par, TOKEN_MINUSMINUS)) { 127 node = make_postfix_node(OPER_POSTDEC, node); 128 } else if (match(par, TOKEN_LBRACKET)) { 129 Node* index = parse_expression(par); // parse inside brackets 130 expect(par, TOKEN_RBRACKET); 131 node = make_subscript_node(node, index); 132 // } else if (match(par, TOKEN_DOT)) { // TODO dot members and arrows 133 // Token id = expect(par, TOKEN_IDENTIFIER); 134 // expr = make_member_node(expr, id); 135 // } else if (match(par, TOKEN_ARROW)) { 136 // Token id = expect(par, TOKEN_IDENTIFIER); 137 // expr = make_ptrmember_node(expr, id); 138 } else if (match(par, TOKEN_LPAREN)) { 139 NodeVec args = parse_func_arguments(par); // parse func call args 140 expect(par, TOKEN_RPAREN); 141 node = make_call_node(node, args); 142 } else { 143 break; 144 } 145 } 146 return node; 147 } 148 149 #define STARTING_ROOT_NODES 32 150 151 Node* 152 make_program_node(Parser* par) 153 { 154 Node* node = (Node*)calloc(1, sizeof(Node)); 155 if (node == NULL) panic("make_program_node: alloc failed"); 156 node->type = NODE_PROGRAM; 157 node->filename = par->filename; 158 node->scope = NULL; 159 node->next = NULL; 160 node->data.program.cap = STARTING_ROOT_NODES; 161 node->data.program.len = 0; 162 node->data.program.decl = (Node**)calloc(STARTING_ROOT_NODES, sizeof(Node)); 163 if (node->data.program.decl == NULL) panic("make_program_node: decls: alloc failed"); 164 return node; 165 } 166 167 Node* 168 make_ident_node(Span name) 169 { 170 Node* node = (Node*)calloc(1, sizeof(Node)); 171 if (node == NULL) panic("make_ident_node: alloc failed"); 172 node->type = NODE_IDENT; 173 node->scope = NULL; 174 node->next = NULL; 175 node->data.ident.name = name; 176 return node; 177 } 178 179 Node* 180 parse_primary(Parser* par) 181 { 182 Token tok = peek(par); 183 if (tok.type == TOKEN_STRING_LITERAL) { return make_string_node(par); } 184 if (tok.type == TOKEN_INT_LITERAL || tok.type == TOKEN_FLOAT_LITERAL) { return make_number_node(par); } 185 if (tok.type == TOKEN_IDENT) { return parse_ident(par); } 186 if (tok.type == TOKEN_LPAREN) { 187 consume(par); // consume '(' 188 Node* node = parse_expression(par); 189 expect(par, TOKEN_RPAREN); 190 return node; 191 } 192 193 const char* name = span_str(par->src, (Span) { .start = tok.start, .end = tok.end }, (char[IDENTSZ]) { 0 }); 194 panic("Expected Primary Expr, but found '%s' (%s at %s:%zu:%zu", 195 name, 196 token_type_str(tok.type), 197 par->filename, 198 tok.line, 199 tok.col); 200 201 return NULL; 202 } 203 204 Node* 205 parse_unary(Parser* par) 206 { 207 Node* inner = NULL; 208 switch (peek(par).type) { 209 case TOKEN_MINUS: 210 consume(par); 211 inner = parse_unary(par); 212 return make_unary_node(OPER_MINUS, inner); 213 case TOKEN_MINUSMINUS: 214 consume(par); 215 inner = parse_unary(par); 216 return make_unary_node(OPER_PREDEC, inner); 217 case TOKEN_BANG: 218 consume(par); 219 inner = parse_unary(par); 220 return make_unary_node(OPER_BANG, inner); 221 // TODO add others '~a' '$a' '*a' '^a' '@a' '&a' 222 case TOKEN_PLUSPLUS: 223 consume(par); 224 inner = parse_unary(par); 225 return make_unary_node(OPER_PREINC, inner); 226 case TOKEN_PLUS: 227 consume(par); 228 return parse_unary(par); 229 default: 230 return parse_postfix(par); 231 } 232 } 233 234 // called by parse_multiplicative 235 Node* 236 parse_term(Parser* par) 237 { 238 return parse_unary(par); 239 }