diff options
-rw-r--r-- | include/parse.h | 12 | ||||
-rw-r--r-- | src/parse.c | 96 |
2 files changed, 101 insertions, 7 deletions
diff --git a/include/parse.h b/include/parse.h index d3cee83..8cc4985 100644 --- a/include/parse.h +++ b/include/parse.h @@ -49,6 +49,7 @@ struct ast_const_global { struct ast_path { const char **segments; + int len, cap; }; struct ast_import { @@ -71,14 +72,11 @@ struct ast_toplevel { } decl; }; -struct ast_subunit { - struct ast_import *imports; - struct ast_toplevel tops[]; -}; - struct ast_unit { - struct ast_subunit *root; - struct ast_subunit imports[]; + struct ast_import *imports; + struct ast_toplevel *tops; + int impsz, implen; + int topsz, toplen; }; void parse(struct lexer *lexer, struct ast_unit *ast); diff --git a/src/parse.c b/src/parse.c index 406752d..a047424 100644 --- a/src/parse.c +++ b/src/parse.c @@ -1 +1,97 @@ +#include <stdarg.h> +#include <stdlib.h> +#include <stdnoreturn.h> #include "parse.h" +#include "util.h" + +static noreturn void +error(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + + fprintf(stderr, "\n"); + exit(EXIT_PARSE); +} + +static void +append(struct ast_path *path, const char *name) +{ + if (path->len >= path->cap) { + path->cap *= 2; + size_t sz = sizeof(const char *) * path->cap; + path->segments = must_realloc(path->segments, sz); + } + + path->segments[path->len++] = name; +} + +static bool +parse_path(struct lexer *lexer, struct ast_path *out) +{ + struct token name; + + if (lex(lexer, &name) != T_NAME) { + error("syntax error: expected path"); + } + + out->segments = must_calloc(1, sizeof(const char *)); + out->segments[0] = name.info.str; + out->len = 1; + out->cap = 1; + + while (match(lexer, T_MODDELIM)) { + if (lex(lexer, &name) != T_NAME) { + error("syntax error: expected name"); + } + append(out, name.info.str); + } + + return true; +} + +static bool +parse_import(struct lexer *lexer, struct ast_import *out) +{ + if (!match(lexer, T_IMPORT)) { + return false; + } + + if (!parse_path(lexer, &out->path)) { + error("syntax error: expected import path"); + } + + struct token token; + if (lex(lexer, &token) == T_NAME) { + out->name = token.info.str; + } else { + unlex(lexer, &token); + out->name = out->path.segments[out->path.len - 1]; + } + + if (!match(lexer, T_SEMICOLON)) { + error("syntax error: expected semicolon"); + } + + return true; +} + +void +parse(struct lexer *lexer, struct ast_unit *ast) +{ + ast->imports = must_calloc(1, sizeof(struct ast_import)); + ast->impsz = 1; + ast->implen = 0; + + struct ast_import import; + while (parse_import(lexer, &import)) { + if (ast->implen >= ast->impsz) { + ast->impsz *= 2; + size_t sz = sizeof(struct ast_import) * ast->impsz; + ast->imports = must_realloc(ast->imports, sz); + } + ast->imports[ast->implen++] = import; + } +} |