diff options
author | kdx <kikoodx@paranoici.org> | 2023-06-09 01:01:27 +0200 |
---|---|---|
committer | kdx <kikoodx@paranoici.org> | 2023-06-09 01:01:27 +0200 |
commit | d898d39c98e575624aed7c19da88c02885bfea0e (patch) | |
tree | 367bfe35dfa70ab6a10f29901d595af54f53fbcd | |
parent | 77d04aa15c9d77e00ec4597375433d93b4cdd9c0 (diff) | |
download | golem-d898d39c98e575624aed7c19da88c02885bfea0e.tar.gz |
that's kinda cool
-rw-r--r-- | src/main.c | 130 |
1 files changed, 109 insertions, 21 deletions
@@ -1,6 +1,24 @@ +#include <ctype.h> #include <stdarg.h> +#include <stdbool.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> + +typedef enum { + TOK_PUNCT, + TOK_NUM, + TOK_EOF, +} TokenType; + +typedef struct Token Token; +struct Token { + TokenType type; + Token *next; + int val; + char *loc; + int len; +}; static void error(const char *fmt, ...) { @@ -13,38 +31,108 @@ error(const char *fmt, ...) { exit(1); } +static void +expect(const Token *tok, TokenType type) +{ + if (tok->type != type) + error("expected a %u", type); +} + +static bool +equal(const Token *tok, const char *op) +{ + return memcmp(tok->loc, op, tok->len) == 0 && op[tok->len] == '\0'; +} + +static Token * +skip(Token *tok, char *s) +{ + if (!equal(tok, s)) + error("expected '%s'", s); + return tok->next; +} + +static int +get_number(Token *tok) +{ + expect(tok, TOK_NUM); + return tok->val; +} + +static Token * +new_token(TokenType type, char *start, char *end) +{ + Token *tok = calloc(1, sizeof(Token)); + if (tok == NULL) + error("calloc failed"); + tok->type = type; + tok->loc = start; + tok->len = end - start; + return tok; +} + +static Token * +tokenize(char *p) +{ + Token head = {0}; + Token *cur = &head; + + while (*p != '\0') { + if (isspace(*p)) { + p++; + continue; + } + + if (isdigit(*p)) { + char *q = p; + const unsigned long val = strtoul(p, &p, 10); + cur = cur->next = new_token(TOK_NUM, q, p); + cur->val = val; + continue; + } + + if (strchr("+-/*", *p) != NULL) { + cur = cur->next = new_token(TOK_PUNCT, p, p + 1); + p += 1; + continue; + } + + error("invalid token"); + } + cur->next = new_token(TOK_EOF, p, p); + + return head.next; +} + int main(int argc, char **argv) { if (argc != 2) error("usage: %s code", argv[0]); - char *p = argv[1]; + Token *tok = tokenize(argv[1]); + /* first token is a number */ printf("main:\n"); - printf("\tLIT %04lu\n", strtoul(p, &p, 10)); + printf("\tLIT %04d\n", get_number(tok)); + tok = tok->next; - while (*p != '\0') { - const char *op; - switch (*p) { - case '+': - op = "ADD"; - break; - case '-': - op = "SUB"; - break; - case '*': - op = "MUL"; - break; - case '/': - op = "DIV"; - break; - default: - error("unexpected character: '%c'", *p); + /* followed by punct then another number */ + while (tok->type != TOK_EOF) { + const char *punct; + expect(tok, TOK_PUNCT); + switch (tok->loc[0]) { + case '+': punct = "ADD"; break; + case '-': punct = "SUB"; break; + case '*': punct = "MUL"; break; + case '/': punct = "DIV"; break; } - p++; - printf("\tLIT %04lu %s\n", strtoul(p, &p, 10), op); + tok = tok->next; + + printf("\tLIT %04d %s\n", get_number(tok), punct); + tok = tok->next; } + expect(tok, TOK_EOF); printf("\tRET\n"); |