/* 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 "filetree.h" typedef void* yyscan_t; struct dirstack { struct dirstack *next; struct dirnode *item; }; struct parser_state { struct dirnode *root; struct dirnode *cur; /// models the current directory stack we're in for simplicity struct dirstack *stackptr; }; struct dirstack* dirstack_push(struct dirstack *stack, struct dirnode *item); struct dirstack* dirstack_pop(struct dirstack *stack); } // Code for the c file %{ #include #include #include #include "parser.h" #include "lexer.h" struct dirstack* dirstack_push(struct dirstack *stack, struct dirnode *item) { struct dirstack *head = calloc(1, sizeof(struct dirstack)); if (!head) { fprintf(stderr, "\033[91m[error] Ran out of memory\033[0m\n"); return NULL; } head->item = item; head->next = stack; return head; } struct dirstack* dirstack_pop(struct dirstack *stack) { if (!stack) { fprintf(stderr, "\033[91m[error] Called `dirstack_pop on an empty stack\033[0m\n"); return NULL; } struct dirstack *next_item = stack->next; free(stack); return next_item; } 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 { char *path; unsigned long num; } %start input %token NEWLINE SPACE %token PROMPT CHDIR LIST %token ROOT PARENT DIRECTORY %token PATHSPEC %token SIZE %term END_OF_FILE %% input : command input | END_OF_FILE { return 0; } ; command : PROMPT CHDIR SPACE ROOT NEWLINE { while (state->stackptr->next) { state->stackptr = dirstack_pop(state->stackptr); } state->cur = state->stackptr->item; } | PROMPT CHDIR SPACE PARENT NEWLINE { state->stackptr = dirstack_pop(state->stackptr); state->cur = state->stackptr->item; } | PROMPT CHDIR SPACE PATHSPEC NEWLINE { // TODO: CLEANUP if (!state) { fprintf(stderr, "\033[91m[error] the fuck\033[0m\n"); } else { printf("searching in %s now for path %s\n", state->cur->name, $4); } // move into the new directory (creating it if it doesn't exist is not necessary, LIST does that) struct dirnode *cur_node = state->cur; // search for the directory name size_t found = 0; int c = -1; size_t i; for (i = 0; i < cur_node->num_dirs; i++) { if (strcmp($4, cur_node->directories[i]->name) == 0) { found = i; c = 0; printf("equal: [%s] and [%s]\n", $4, cur_node->directories[i]->name); } else { printf("not equal: [%s] and [%s]\n", $4, cur_node->directories[i]->name); } } if (c == -1) { fprintf(stderr, "\033[91m[error] got no such directory lol\033[0m\n"); // TODO: error, directory not found } else { printf("found it\n"); } struct dirnode *next = cur_node->directories[found]; // actually move into the new directory state->stackptr = dirstack_push(state->stackptr, next); state->cur = next; } | PROMPT LIST NEWLINE output | NEWLINE ; output : listing NEWLINE output | ; listing : DIRECTORY SPACE PATHSPEC { struct dirnode *item = calloc(1, sizeof(struct dirnode)); if (!item) { // TODO: error handling } item->name = $3; add_directory(state->cur, item); printf("know about %zu dirs now!\n", state->cur->num_dirs); } | SIZE SPACE PATHSPEC { struct filenode *item = calloc(1, sizeof(struct filenode)); if (!item) { // TODO: error handling } item->name = $3; item->size = $1; add_file(state->cur, item); } ; %% int main(void) { struct dirnode *root = calloc(1, sizeof(struct dirnode)); if (!root) { fprintf(stderr, "\033[91m[error] Ran out of memory\033[0m\n"); return EXIT_FAILURE; } root->name = "\0"; struct dirstack *stack_ptr = dirstack_push(NULL, root); 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->root = root; state->cur = root; state->stackptr = stack_ptr; 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); // TODO: evaluation (bottom-up computation of sizes using a dirstack) return 0; }