From 01a9392ad6051878e217bffeffd6261ccf994c42 Mon Sep 17 00:00:00 2001 From: Anton Kling Date: Fri, 17 Nov 2023 23:58:14 +0100 Subject: Minibox: Add a somewhat improved shell This shell actually lexes and produces a AST which makes it easier to add features and will makes it more difficult to introduce bugs. So basically it is just better code. --- userland/minibox/utilities/sh/ast.c | 99 +++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 userland/minibox/utilities/sh/ast.c (limited to 'userland/minibox/utilities/sh/ast.c') diff --git a/userland/minibox/utilities/sh/ast.c b/userland/minibox/utilities/sh/ast.c new file mode 100644 index 0000000..64dd725 --- /dev/null +++ b/userland/minibox/utilities/sh/ast.c @@ -0,0 +1,99 @@ +#include "ast.h" +#include +#include +#include +#include + +void free_ast_command(struct AST *ast) { + free_ast(ast->children); + free_ast(ast->pipe_rhs); +} + +void free_ast(struct AST *ast) { + for (; ast;) { + if (AST_COMMAND == ast->type) + free_ast_command(ast); + struct AST *old = ast; + ast = ast->next; + free(old); + } +} + +struct AST *allocate_ast(void) { + struct AST *r = malloc(sizeof(struct AST)); + memset(r, 0, sizeof(struct AST)); + return r; +} + +int parse_command(struct TOKEN **token_ptr, struct AST *cur) { + struct TOKEN *token = *token_ptr; + if (TOKEN_CHARS != token->type) + return 0; + cur->type = AST_COMMAND; + cur->val.type = AST_VALUE_STRING; + cur->val.string = token->string_rep; + // Parse the arguments + if (token->next && TOKEN_CHARS == token->next->type) { + token = token->next; + cur->children = allocate_ast(); + struct AST *child = cur->children; + for (;;) { + child->type = AST_EXPRESSION; + child->val.type = AST_VALUE_STRING; + child->val.string = token->string_rep; + if (!token->next) + break; + if (TOKEN_CHARS != token->next->type) + break; + token = token->next; + child->next = allocate_ast(); + child = child->next; + } + } + token = token->next; + // Parse the stream modifier "prog > file.txt" + if (token && + (TOKEN_STREAM == token->type || TOKEN_STREAM_APPEND == token->type)) { + cur->file_out_append = (TOKEN_STREAM_APPEND == token->type); + // TODO: Allow it to be modified + cur->file_out_fd_to_use = STDOUT_FILENO; + token = token->next; + cur->file_out = token->string_rep; + token = token->next; + } + // Parse pipe '|' + if (token && TOKEN_PIPE == token->type) { + cur->pipe_rhs = allocate_ast(); + token = token->next; + if (!parse_command(&token, cur->pipe_rhs)) { + fprintf(stderr, "Expected command after |."); + exit(1); + } + } + *token_ptr = token; + return 1; +} + +struct AST *generate_ast(struct TOKEN *token) { + struct AST *head = NULL; + struct AST *prev = NULL; + for (; token;) { + struct AST *cur = allocate_ast(); + if (prev) + prev->next = cur; + if (parse_command(&token, cur)) { + } else if (TOKEN_AND == token->type) { + cur->type = AST_CONDITIONAL_AND; + token = token->next; + } else if (TOKEN_NOT == token->type) { + cur->type = AST_CONDITIONAL_NOT; + token = token->next; + } else { + token = token->next; + } + if (!head) + head = cur; + prev = cur; + } + return head; +} -- cgit v1.2.3