178 lines
5.3 KiB
Text
178 lines
5.3 KiB
Text
|
/* 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 <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#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 <cval> CRATE_ID
|
||
|
%token <num> 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;
|
||
|
}
|