summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkdx <kikoodx@paranoici.org>2023-06-09 01:01:27 +0200
committerkdx <kikoodx@paranoici.org>2023-06-09 01:01:27 +0200
commitd898d39c98e575624aed7c19da88c02885bfea0e (patch)
tree367bfe35dfa70ab6a10f29901d595af54f53fbcd
parent77d04aa15c9d77e00ec4597375433d93b4cdd9c0 (diff)
downloadgolem-d898d39c98e575624aed7c19da88c02885bfea0e.tar.gz
that's kinda cool
-rw-r--r--src/main.c130
1 files changed, 109 insertions, 21 deletions
diff --git a/src/main.c b/src/main.c
index 1bcb71c..666f847 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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");