From 9e22c31a2f95b7f91ad9fec0873f3fa21366c272 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Sat, 14 Feb 2026 00:11:26 -0500 Subject: [PATCH] core: Add initial lexer and parser sources Signed-off-by: Ian Moffett --- core/lexer.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++ core/parser.c | 51 +++++++++++++++++++++++++ core/rifle.c | 7 ++++ inc/rifle/lexer.h | 18 +++++++++ inc/rifle/parser.h | 13 +++++++ 5 files changed, 182 insertions(+) create mode 100644 core/lexer.c create mode 100644 core/parser.c create mode 100644 inc/rifle/lexer.h create mode 100644 inc/rifle/parser.h diff --git a/core/lexer.c b/core/lexer.c new file mode 100644 index 0000000..bacde50 --- /dev/null +++ b/core/lexer.c @@ -0,0 +1,93 @@ +#include +#include +#include +#include +#include "rifle/lexer.h" +#include "rifle/trace.h" + +/* + * Returns true if the given input character is a + * whitespace character + */ +static inline bool +lexer_is_ws(char c) +{ + switch (c) { + case '\n': + case '\t': + case '\r': + case '\f': + case ' ': + return true; + } + + return false; +} + +/* + * Consume a single byte from the input source file + * while skipping any whitespace characters. + * + * @state: Compiler state + * @keep_ws: If true, preserve whitespace + * + * Returns the consumed character on success, otherwise + * '\0' upon failure. + */ +static char +lexer_nom(struct rifle_state *state, bool keep_ws) +{ + char c; + + if (state == NULL) { + return '\0'; + } + + while (read(state->in_fd, &c, 1) > 0) { + if (lexer_is_ws(c) && !keep_ws) { + continue; + } + + return c; + } + + return '\0'; +} + +int +lexer_scan(struct rifle_state *state, struct token *res) +{ + char c; + + if (state == NULL || res == NULL) { + return -1; + } + + if ((c = lexer_nom(state, false)) == '\0') { + return -1; + } + + switch (c) { + case '+': + res->type = TT_PLUS; + res->c = c; + return 0; + case '-': + res->type = TT_MINUS; + res->c = c; + return 0; + case '*': + res->type = TT_STAR; + res->c = c; + return 0; + case '/': + res->type = TT_SLASH; + res->c = c; + return 0; + default: + trace_error(state, "unexpected token '%c'\n", c); + break; + } + + return -1; +} diff --git a/core/parser.c b/core/parser.c new file mode 100644 index 0000000..b2bed0b --- /dev/null +++ b/core/parser.c @@ -0,0 +1,51 @@ +#include +#include +#include "rifle/parser.h" +#include "rifle/token.h" +#include "rifle/trace.h" +#include "rifle/lexer.h" +#include "rifle/state.h" + +/* Symbolic token */ +#define symtok(tok) \ + "[" tok "]" + +/* Quoted token */ +#define qtok(tok) \ + "'" tok "'" + +/* Convert token to string */ +#define tokstr1(tt) \ + toktab[(tt)] + +/* Convert token to string */ +#define tokstr(tok) \ + tokstr1((tok)->type) + +/* + * Table used to convert token constants into human + * readable strings + */ +static const char *toktab[] = { + [TT_NONE] = symtok("none"), + [TT_PLUS] = qtok("+"), + [TT_MINUS] = qtok("-"), + [TT_STAR] = qtok("*"), + [TT_SLASH] = qtok("/") +}; + +int +parser_parse(struct rifle_state *state) +{ + struct token tok; + + if (state == NULL) { + return 0; + } + + while (lexer_scan(state, &tok) == 0) { + trace_debug("got %s\n", tokstr(&tok)); + } + + return 0; +} diff --git a/core/rifle.c b/core/rifle.c index 76ac466..c7460a8 100644 --- a/core/rifle.c +++ b/core/rifle.c @@ -2,6 +2,7 @@ #include #include #include "rifle/state.h" +#include "rifle/parser.h" /* Compiler version */ #define RIFLE_VERSION "0.0.1" @@ -38,6 +39,11 @@ compile(const char *in_path) return -1; } + if (parser_parse(&state) < 0) { + rifle_state_destroy(&state); + return -1; + } + rifle_state_destroy(&state); return 0; } @@ -72,5 +78,6 @@ main(int argc, char **argv) printf("fatal: no input files\n"); return -1; } + return 0; } diff --git a/inc/rifle/lexer.h b/inc/rifle/lexer.h new file mode 100644 index 0000000..474cbb4 --- /dev/null +++ b/inc/rifle/lexer.h @@ -0,0 +1,18 @@ +#ifndef RIFLE_LEXER_H +#define RIFLE_LEXER_H 1 + +#include +#include "rifle/token.h" +#include "rifle/state.h" + +/* + * Scan a single token from the source input + * + * @state: Compiler state + * @res: Result is written here + * + * Returns zero on success + */ +int lexer_scan(struct rifle_state *state, struct token *res); + +#endif /* !RIFLE_LEXER_H */ diff --git a/inc/rifle/parser.h b/inc/rifle/parser.h new file mode 100644 index 0000000..0353c42 --- /dev/null +++ b/inc/rifle/parser.h @@ -0,0 +1,13 @@ +#ifndef RIFLE_PARSER_H +#define RIFLE_PARSER_H 1 + +#include "rifle/state.h" + +/* + * Begin parsing the input source file + * + * @state: Compiler state + */ +int parser_parse(struct rifle_state *state); + +#endif /* !RIFLE_PARSER_H */