/* 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 { typedef void* yyscan_t; #define NUM_PILES 9 // a stack of crates, implemented as linked list (b/c it makes movement easier) struct stack_item { struct stack_item* next; char crate_id; }; struct parser_state { // points to the topmost item in the stack struct stack_item** stacks; unsigned stack_idx; }; } // 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); } %} // 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; char cval; } %start input %token NEWLINE SPACE %token CRATE_DELIM_OPEN CRATE_DELIM_CLOSE %token CRATE_ID %token NUMBER %token MOVE_OP ORIGIN DEST %term END_OF_FILE %% input : initialization NEWLINE movement END_OF_FILE { return 0; } ; initialization : line NEWLINE initialization | line NEWLINE ; line : item SPACE line | item ; item : CRATE_DELIM_OPEN CRATE_ID CRATE_DELIM_CLOSE { // printf("Pushing %c onto stack #%lu\n", $2, state->stack_idx); struct stack_item* it = calloc(1, sizeof(struct stack_item)); // TODO(feliix42): error handling on failed alloc it->crate_id = $2; // mind we build the stack top down, which means we have to traverse it when adding a new elem if (!state->stacks[state->stack_idx]) { state->stacks[state->stack_idx] = it; } else { struct stack_item* tail = state->stacks[state->stack_idx]; while (tail->next != NULL) { tail = tail->next; } tail->next = it; } state->stack_idx = (state->stack_idx + 1) % NUM_PILES; } | SPACE NUMBER SPACE { state->stack_idx = (state->stack_idx + 1) % NUM_PILES; } | SPACE SPACE SPACE { state->stack_idx = (state->stack_idx + 1) % NUM_PILES; } ; movement : expr NEWLINE movement | expr NEWLINE | NEWLINE ; expr : MOVE_OP NUMBER ORIGIN NUMBER DEST NUMBER { // Source: $4, Dst: $6, repeat $2 times // printf("move %lu from %lu to %lu", $2, $4, $6); for (unsigned long i = 0; i < $2; i++) { // get the current element struct stack_item* it = state->stacks[$4 -1]; if (!it) { // TODO(feliix42): use yyerror? fprintf(stderr, "\033[91m[parser error] tried to pop from empty stack\n\033[0m"); break; } // delete old references state->stacks[$4 -1] = it->next; // insert on new stack it->next = state->stacks[$6 -1]; state->stacks[$6 -1] = it; } } ; %% int main(void) { struct parser_state parser_state; parser_state.stack_idx = 0; parser_state.stacks = calloc(NUM_PILES, sizeof(struct stack_item*)); if (!parser_state.stacks) { fprintf(stderr, "\033[91m[error] Could not initialize parser state\033[0m\n"); return EXIT_FAILURE; } yyscan_t scanner; if (yylex_init(&scanner)) { fprintf(stderr, "\033[91m[error] Could not initialize lexer\033[0m\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); printf("Top Stack IDs: "); struct stack_item* cur; for (int i = 0; i < NUM_PILES; i++) { cur = parser_state.stacks[i]; if (cur) { printf("%c", cur->crate_id); } else { printf(" "); } } printf("\n"); return 0; }