208 lines
6.3 KiB
Text
208 lines
6.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 {
|
|
#include <stdbool.h>
|
|
|
|
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;
|
|
// whether the crane is generation two (task 2)
|
|
bool is_gen_two;
|
|
};
|
|
}
|
|
|
|
// Code for the c file
|
|
%{
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdbool.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);
|
|
|
|
if (state->is_gen_two) {
|
|
struct stack_item* it = state->stacks[$4 - 1];
|
|
for (unsigned long i = 1; i < $2; i++) {
|
|
if (!it) {
|
|
// TODO(feliix42): use yyerror?
|
|
fprintf(stderr, "\033[91m[parser error] tried to pop from empty stack\n\033[0m");
|
|
break;
|
|
}
|
|
|
|
it = it->next;
|
|
}
|
|
|
|
struct stack_item* tmp = state->stacks[$4 - 1];
|
|
state->stacks[$4 - 1] = it->next;
|
|
|
|
it->next = state->stacks[$6 - 1];
|
|
state->stacks[$6 - 1] = tmp;
|
|
} else {
|
|
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(int argc, char** argv) {
|
|
struct parser_state parser_state;
|
|
parser_state.stack_idx = 0;
|
|
|
|
if (argc > 1 && argv[1][0] == '2') {
|
|
parser_state.is_gen_two = true;
|
|
} else {
|
|
parser_state.is_gen_two = false;
|
|
}
|
|
|
|
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;
|
|
}
|