From 196660ccb172f5c7244fabef1ab1313b0c6c5bd9 Mon Sep 17 00:00:00 2001 From: Felix Suchert Date: Sun, 25 Dec 2022 21:15:50 +0100 Subject: [PATCH] Add day 1, task 1 --- day_1/Makefile | 54 ++++++++++++++++++++++++ day_1/lexer.l | 53 +++++++++++++++++++++++ day_1/parser.y | 111 +++++++++++++++++++++++++++++++++++++++++++++++++ day_1/state.c | 15 +++++++ 4 files changed, 233 insertions(+) create mode 100644 day_1/Makefile create mode 100644 day_1/lexer.l create mode 100644 day_1/parser.y create mode 100644 day_1/state.c diff --git a/day_1/Makefile b/day_1/Makefile new file mode 100644 index 0000000..545eddb --- /dev/null +++ b/day_1/Makefile @@ -0,0 +1,54 @@ +CC := clang +YACC := bison +LEX := flex +CFLAGS := -std=c17 -Wpedantic -Wall -Wextra +BUILD := ./build +INCLUDE := -I./ +OBJ_DIR := $(BUILD)/objects +APP_DIR := $(BUILD)/bin +TARGET := day_1 + +SRC := $(wildcard ./*.cpp) lexer.c parser.c + +OBJECTS := $(SRC:%.c=$(OBJ_DIR)/%.o) + +# targets +all: build $(APP_DIR)/$(TARGET) + +run: all + $(APP_DIR)/$(TARGET) + +flex: + $(LEX) --outfile=lexer.c --header-file=lexer.h lexer.l + +bison: + $(YACC) --output=parser.c parser.y + +generate: flex bison + +$(OBJ_DIR)/%.o: %.c + @mkdir -p $(@D) + $(CC) $(CFLAGS) $(INCLUDE) -o $@ -c $< + +$(APP_DIR)/$(TARGET): flex bison $(OBJECTS) + @mkdir -p $(@D) + $(CC) $(CFLAGS) $(INCLUDE) $(LDFLAGS) -o $(APP_DIR)/$(TARGET) $(OBJECTS) + +.PHONY: all build clean debug release + +build: + @mkdir -p $(APP_DIR) + @mkdir -p $(OBJ_DIR) + +debug: CFLAGS += -DDEBUG -g +debug: all + +sanitize: CFLAGS += -DDEBUG -g -fsanitize=address +sanitize: all + +release: CFLAGS += -O2 +release: all + +clean: + -@rm -rvf $(BUILD) + -@rm -rvf {lexer.c,parser.c} {lexer.h,parser.h} diff --git a/day_1/lexer.l b/day_1/lexer.l new file mode 100644 index 0000000..6e92a74 --- /dev/null +++ b/day_1/lexer.l @@ -0,0 +1,53 @@ +%{ /* -*- C -*- */ +#include +#include +#include "parser.h" +%} + +%option warn nodefault + +/* makes the scanner terminate after reaching <> instead of assuming a new input was provided */ +%option noyywrap +/* disable some unused functionality, add scanner tracking */ +%option nounput noinput batch debug + +/* gimme a reentrant parser (overkill but more pure) */ +%option reentrant + +%option bison-bridge + + +NL [\n] +NUM [0-9] + + +%% + +{NL} { + return NEWLINE; + } +{NUM}+ { + unsigned num = strtoul(yytext, NULL, 10); + printf("number: %d\n", num); + yylval->num = num; + return NUMBER; + } +<> { + return END_OF_FILE; + } +. { + printf("[error] Encountered unexpected token %s\n", yytext); + return 0; + } + +%% + +/*int main() {*/ + /*std::cout << "hello" << std::endl;*/ + + /*yyFlexLexer scanner;*/ + /*scanner.yylex();*/ + + /*std::cout << "done" << std::endl;*/ + /*return 0;*/ +/*}*/ diff --git a/day_1/parser.y b/day_1/parser.y new file mode 100644 index 0000000..7818687 --- /dev/null +++ b/day_1/parser.y @@ -0,0 +1,111 @@ +/* Require bison minimal version */ +%require "3.2" + +/* write out a header file containing the token defines */ +%header + +// Code for the c file +%{ + #include + #include + #include "parser.h" + #include "lexer.h" + + void push_value(struct parser_state* state) { + // TODO(feliix42): error handling here? + state->calorie_list = realloc(state->calorie_list, state->size+1); + state->calorie_list[state->size] = state->tmp_val; + state->tmp_val = 0; + state->size++; + } + + void yyerror(struct parser_state* state, yyscan_t scanner, const char* msg) { + (void)state; + (void)scanner; + fprintf(stderr, "\033[93mSyntax Error: %s\033[0m\n", msg); + } +%} + +// Code for the header file generated by bison +%code requires { + typedef void* yyscan_t; + + struct parser_state { + unsigned tmp_val; + unsigned* calorie_list; + size_t size; + }; +} + +// define a reentrant parser +%define api.pure + +// enable parser tracing and detailed error messages (plus Lookahead Correction) +%define parse.trace +%define parse.error detailed +%define parse.lac full + +%lex-param { yyscan_t scanner } +%parse-param { struct parser_state* state } +%parse-param { yyscan_t scanner } + +%union { + unsigned long num; +} + + +%start input +%token NEWLINE END_OF_FILE +%token NUMBER + +%% + +input + : line input + | END_OF_FILE { /* done. */ } + ; + +line + : NUMBER NEWLINE { state->tmp_val += yylval.num; } + | NEWLINE { push_value(state); } + ; + +%% + +int main(int argc, char** argv) { + struct parser_state* parser_state = calloc(1, sizeof(struct parser_state)); + if (!parser_state) { + fprintf(stderr, "[error] failed to allocate parser state\n"); + return EXIT_FAILURE; + } + + yyscan_t scanner; + /*YY_BUFFER_STATE state;*/ + + printf("Hello World\n"); + if (yylex_init(&scanner)) { + fprintf(stderr, "\033[91m[error] Could not initialize lexer\n"); + return EXIT_FAILURE; + } + + if (yyparse(parser_state, scanner)) { + // TODO: Error handling https://www.gnu.org/software/bison/manual/html_node/Parser-Function.html + // error during parse occured + return EXIT_FAILURE; + } + + yylex_destroy(scanner); + + // task 1.1 + unsigned max_val = 0; + for (int i = 0; i < parser_state->size; i++) { + if (parser_state->calorie_list[i] > max_val) { + max_val = parser_state->calorie_list[i]; + } + } + + printf("Largest individual calorie load: %d\n", max_val); + + + return 0; +} diff --git a/day_1/state.c b/day_1/state.c new file mode 100644 index 0000000..3323891 --- /dev/null +++ b/day_1/state.c @@ -0,0 +1,15 @@ +#include + +struct parser_state { + unsigned tmp_val; + unsigned* calorie_list; + size_t size; +}; + +void push_value(struct parser_state* state) { + // TODO(feliix42): error handling here? + state->calorie_list = realloc(state->calorie_list, state->size+1); + state->calorie_list[state->size] = state->tmp_val; + state->tmp_val = 0; + state->size++; +}