223 lines
7.7 KiB
Text
223 lines
7.7 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 "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 <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#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 <path> PATHSPEC
|
|
%token <num> 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;
|
|
}
|