summaryrefslogtreecommitdiff
path: root/21sh/ll-expr/src/lexer/lexer.c
diff options
context:
space:
mode:
Diffstat (limited to '21sh/ll-expr/src/lexer/lexer.c')
-rw-r--r--21sh/ll-expr/src/lexer/lexer.c104
1 files changed, 104 insertions, 0 deletions
diff --git a/21sh/ll-expr/src/lexer/lexer.c b/21sh/ll-expr/src/lexer/lexer.c
new file mode 100644
index 0000000..3b3d29f
--- /dev/null
+++ b/21sh/ll-expr/src/lexer/lexer.c
@@ -0,0 +1,104 @@
+#include "lexer.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct lexer *lexer_new(const char *input)
+{
+ struct lexer *new = malloc(sizeof(struct lexer));
+ new->input = input;
+ new->pos = 0;
+ return new;
+}
+
+void lexer_free(struct lexer *lexer)
+{
+ free(lexer);
+}
+
+struct template
+{
+ char value;
+ enum token_type type;
+};
+
+struct template templates[] = {
+ { '+', TOKEN_PLUS }, { '-', TOKEN_MINUS }, { '*', TOKEN_MUL },
+ { '/', TOKEN_DIV }, { '(', TOKEN_LEFT_PAR }, { ')', TOKEN_RIGHT_PAR },
+ { '\0', TOKEN_EOF }, { 0, TOKEN_ERROR }
+};
+
+static ssize_t parse_number(struct lexer *l)
+{
+ union
+ {
+ const char *cc;
+ char *c;
+ } cast;
+ cast.cc = l->input + l->pos;
+ char *in = cast.c;
+ size_t t = 0;
+ while (in[t] && in[t] >= '0' && in[t] <= '9')
+ t++;
+ char tmp = in[t];
+ in[t] = '\0';
+ ssize_t res = atoi(in);
+ in[t] = tmp;
+ return res;
+}
+
+struct token lexer_next_token(struct lexer *lexer)
+{
+ for (; lexer->input[lexer->pos] && lexer->input[lexer->pos] == ' ';
+ lexer->pos++)
+ continue;
+ for (int i = 0; i < 7; i++)
+ {
+ if (lexer->input[lexer->pos] == templates[i].value)
+ {
+ lexer->current_tok.type = templates[i].type;
+ return lexer->current_tok;
+ }
+ }
+ if (lexer->input[lexer->pos] > '9' || lexer->input[lexer->pos] < '0')
+ {
+ lexer->current_tok.type = TOKEN_ERROR;
+ fprintf(stderr, "lexer: invalid token %c\n", lexer->input[lexer->pos]);
+ return lexer->current_tok;
+ }
+ else
+ {
+ lexer->current_tok.type = TOKEN_NUMBER;
+ lexer->current_tok.value = parse_number(lexer);
+ return lexer->current_tok;
+ }
+}
+
+struct token lexer_peek(struct lexer *lexer)
+{
+ return lexer_next_token(lexer);
+}
+
+static size_t count_numbers(ssize_t value)
+{
+ if (value == 0)
+ return 1;
+ size_t size = 0;
+ while (value)
+ {
+ size++;
+ value /= 10;
+ }
+ return size;
+}
+
+struct token lexer_pop(struct lexer *lexer)
+{
+ struct token res = lexer_next_token(lexer);
+ if (res.type == TOKEN_NUMBER)
+ lexer->pos += count_numbers(res.value);
+ else
+ lexer->pos++;
+ return res;
+}