diff --git a/day_10/Makefile b/day_10/Makefile new file mode 100644 index 0000000..6eb5dcf --- /dev/null +++ b/day_10/Makefile @@ -0,0 +1,3 @@ +TARGET := day_10 + +include ../Makefile.common.mk diff --git a/day_10/input.txt b/day_10/input.txt new file mode 100644 index 0000000..04aee45 --- /dev/null +++ b/day_10/input.txt @@ -0,0 +1,141 @@ +addx 1 +noop +addx 5 +addx -1 +addx 5 +addx 1 +noop +noop +addx 2 +addx 5 +addx 2 +addx 1 +noop +addx -21 +addx 26 +addx -6 +addx 8 +noop +noop +addx 7 +noop +noop +noop +addx -37 +addx 13 +addx -6 +addx -2 +addx 5 +addx 25 +addx 2 +addx -24 +addx 2 +addx 5 +addx 5 +noop +noop +addx -2 +addx 2 +addx 5 +addx 2 +addx 7 +addx -2 +noop +addx -8 +addx 9 +addx -36 +noop +noop +addx 5 +addx 6 +noop +addx 25 +addx -24 +addx 3 +addx -2 +noop +addx 3 +addx 6 +noop +addx 9 +addx -8 +addx 5 +addx 2 +addx -7 +noop +addx 12 +addx -10 +addx 11 +addx -38 +addx 22 +addx -15 +addx -3 +noop +addx 32 +addx -25 +addx -7 +addx 11 +addx 5 +addx 10 +addx -9 +addx 17 +addx -12 +addx 2 +noop +addx 2 +addx -15 +addx 22 +noop +noop +noop +addx -35 +addx 7 +addx 21 +addx -25 +noop +addx 3 +addx 2 +noop +addx 7 +noop +addx 3 +noop +addx 2 +addx 9 +addx -4 +addx -2 +addx 5 +addx 2 +addx -2 +noop +addx 7 +addx 2 +addx -39 +addx 2 +noop +addx 1 +noop +addx 5 +addx 24 +addx -20 +addx 1 +addx 5 +noop +noop +addx 4 +noop +addx 1 +noop +addx 4 +addx 3 +noop +addx 2 +noop +noop +addx 1 +addx 2 +noop +addx 3 +noop +noop + diff --git a/day_10/lexer.l b/day_10/lexer.l new file mode 100644 index 0000000..875b8ac --- /dev/null +++ b/day_10/lexer.l @@ -0,0 +1,51 @@ +%{ +#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] +SPACE " " + +NOP "noop" +ADD "addx" + +/*general definitions*/ +NUM [0-9\-] + +%% + +{NL} { return NEWLINE; } +{SPACE} { /* return SPACE; */ } +{NOP} { return NOP; } +{ADD} { return ADDX; } + +{NUM}+ { + int num = atoi(yytext); + yylval->num = num; + return NUM; + } + +<> { + return END_OF_FILE; + } +. { + printf("[error] Encountered unexpected token %s\n", yytext); + return 0; + } + +%% diff --git a/day_10/parser.y b/day_10/parser.y new file mode 100644 index 0000000..9fd9093 --- /dev/null +++ b/day_10/parser.y @@ -0,0 +1,132 @@ +/* Require bison minimal version */ +%require "3.2" + +/* write out a header file containing the token defines */ +%header + +// Code for the header file generated by bison +%code requires { + #include + + typedef void* yyscan_t; + + struct parser_state { + /// Program Counter + size_t cycle; + + /// Contents of register X + long reg; + + /// Task 1 + long sum; + size_t next_target_cycle; + }; +} + +// Code for the c file +%{ + #include + #include + #include "parser.h" + #include "lexer.h" + + 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); + } + + void increment_cycle(struct parser_state *state) { + state->cycle++; + + if (state->cycle == state->next_target_cycle) { + long tmp = state->cycle * state->reg; + printf("[info] Register contents at cycle %zu: %ld\n", state->cycle, state->reg); + state->sum += tmp; + + if (state->next_target_cycle < 220) { + state->next_target_cycle += 40; + } + } + } +%} + +// 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 { + int num; +} + +%start input +%token NEWLINE +%token NOP ADDX +%token NUM +%term END_OF_FILE + +%% + +input + : line input + | END_OF_FILE { return 0; } + ; + +line + : instruction NEWLINE + | NEWLINE + ; + +instruction + : NOP { increment_cycle(state); } + | ADDX NUM { + increment_cycle(state); + increment_cycle(state); + + state->reg += $2; + } + ; + + +%% + + +int main(void) { + struct parser_state *state = calloc(1, sizeof(struct parser_state)); + if (!state) { + fprintf(stderr, "\033[91m[error] Ran out of memory\033[0m\n"); + return EXIT_FAILURE; + } + + state->reg = 1; + state->next_target_cycle = 20; + + yyscan_t scanner; + if (yylex_init(&scanner)) { + fprintf(stderr, "\033[91m[error] Could not initialize lexer\033[0m\n"); + return EXIT_FAILURE; + } + + if (yyparse(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 + printf("Sum of signal strengths: %ld\n", state->sum); + + free(state); + + return 0; +}