diff options
| author | Nakidai <nakidai@disroot.org> | 2025-03-24 21:01:37 +0300 |
|---|---|---|
| committer | Nakidai <nakidai@disroot.org> | 2025-03-24 21:01:37 +0300 |
| commit | f312b357ab2ec3cf83a67945f3641b964a59e8d2 (patch) | |
| tree | 425f3371eee770f64e268e9964dba29ad17bd410 /parser.c | |
| parent | ad9d6a199db7c28f8b20f131dfb55a26e0e251de (diff) | |
| download | 3cl-f312b357ab2ec3cf83a67945f3641b964a59e8d2.tar.gz 3cl-f312b357ab2ec3cf83a67945f3641b964a59e8d2.zip | |
Add code
Diffstat (limited to 'parser.c')
| -rw-r--r-- | parser.c | 130 |
1 files changed, 130 insertions, 0 deletions
diff --git a/parser.c b/parser.c new file mode 100644 index 0000000..87eb498 --- /dev/null +++ b/parser.c @@ -0,0 +1,130 @@ +#include "cccl.h" + +#include <assert.h> +#include <err.h> +#include <stddef.h> +#include <stdlib.h> + + +static enum cccl_NodeType get_nodetype(char c) +{ + switch (c) + { +#define X(char, name) case char: return cccl_Node_##name + X('^', PUSHZERO); + X('+', INCREMENT); + X('-', DECREMENT); + X('*', ADD); + X('~', SUBTRACT); + X('%', REVERSE); + X('=', ASSIGN); + X('!', DELETE); + X('$', PUSHVAR); + X('&', ASSIGNLOCAL); + X('<', OUTPUT); + X('>', INPUT); + X('{', PROCEDURE); + X('}', PROCEDURE); + X('@', CALL); + X('(', INFINITE); + X(')', INFINITE); + X('[', REPEAT); + X(']', REPEAT); + X('#', END); + X(':', CONTINUE); + X('?', CONDITIONAL); + X(';', CONDITIONAL); +#undef X + } + err(1, "Unrecognized command: [%d] %c", c, c); +} + + +struct cccl_Node *cccl_parse(struct cccl_Token tokens[], size_t tokens_length, enum cccl_NodeType type, char value) +{ + struct cccl_Node *res = malloc(sizeof(*res)); + *res = (struct cccl_Node) + { + .type = type, + .in = NULL, + .in_length = 0, + .value = value, + }; + + for (size_t i = 0; i < tokens_length; ++i) + { + switch (tokens[i].type) + { + case cccl_Token_COMMAND: case cccl_Token_COMMANDWITHARG: case cccl_Token_BLOCKSTART: + { + if (!res->in) + { + res->in_length = 1; + res->in = malloc(sizeof(*res->in)); + } else + { + ++res->in_length; + res->in = realloc(res->in, sizeof(*res->in) * res->in_length); + } + } break; + } + + switch (tokens[i].type) + { + case cccl_Token_COMMAND: + { + res->in[res->in_length - 1] = malloc(sizeof(struct cccl_Node)); + *res->in[res->in_length - 1] = (struct cccl_Node) + { + .type = get_nodetype(tokens[i].value), + }; + } break; + case cccl_Token_COMMANDWITHARG: + { + assert(i + 1 != tokens_length); + res->in[res->in_length - 1] = malloc(sizeof(struct cccl_Node)); + *res->in[res->in_length - 1] = (struct cccl_Node) + { + .type = get_nodetype(tokens[i].value), + .value = tokens[i + 1].value, + }; + } break; + case cccl_Token_BLOCKSTART: + { + assert(i > 0); + char opening = tokens[i].value, closing; + switch (tokens[i].value) + { + break; case '{': closing = '}'; + break; case '(': closing = ')'; + break; case '[': closing = ']'; + break; case '?': closing = ';'; + } + + size_t oldi = i; + int depth = 1; + for (; i < tokens_length; ++i) + { + if (tokens[i].value == opening) + ++depth; + else if (tokens[i].value == closing) + --depth; + + if (depth == 0) + goto end; + } + errx(1, "No matching bracket for %c", opening); + +end: + res->in[res->in_length - 1] = cccl_parse( + tokens + oldi + 1, + i - oldi - 1, + get_nodetype(tokens[i].value), + tokens[oldi - 1].value + ); + } break; + } + } + + return res; +} |