diff --git a/README.md b/README.md index e6dc364..5f0615c 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # msh -msh is a WIP shell with the goal of being portable to older operating systems, namely classic Windows and classic Mac OS. While the former already has a shell, the aim for both is to provide something closer to what linux shells provide (with exceptions ofc). +msh is a WIP shell with the goal of being portable to older operating systems, namely classic Windows and classic Mac OS. While the former already has a shell, the aim for both is to provide something equivalant Unix's bourne shell (as well as some from bash/zsh). It's written without the C standard library. Ports instead must implement `src/system/system.h` accordingly. It's also written in C89/C99 (mostly the former as it's needed for some compilers, but if C99 is supported by a platform's backend then it'll probably be used). diff --git a/src/exec.c b/src/exec.c index b9a67b5..7cea034 100644 --- a/src/exec.c +++ b/src/exec.c @@ -1,3 +1,32 @@ +/* + Copyright 2026 msh team + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ #include "builtins/builtins.h" #include "lexer/lexer.h" #include "system/system.h" diff --git a/src/lexer/lexer.c b/src/lexer/lexer.c index ee42c4c..ec7a321 100644 --- a/src/lexer/lexer.c +++ b/src/lexer/lexer.c @@ -64,6 +64,35 @@ void msh_lexer_push_item(msh_lexer *lexer, msh_lexer_item_type type, char *buf, lexer->item_list_cur = lexer->item_list_cur->next; }; +/* function for either pushing a regular word or pushing a keyword to the + * buffer. */ +static void word_push(msh_lexer *lexer, char *cur_word_buf, int *n) { + int hash = 0; + cur_word_buf[*n] = '\0'; + hash = str_hash(cur_word_buf); + switch (hash) { + case MSH_LEXER_ITEM_TYPE_WORD_KEYWORD_IF: + case MSH_LEXER_ITEM_TYPE_WORD_KEYWORD_THEN: + case MSH_LEXER_ITEM_TYPE_WORD_KEYWORD_ELSE: + case MSH_LEXER_ITEM_TYPE_WORD_KEYWORD_ELIF: + case MSH_LEXER_ITEM_TYPE_WORD_KEYWORD_FI: + case MSH_LEXER_ITEM_TYPE_WORD_KEYWORD_CASE: + case MSH_LEXER_ITEM_TYPE_WORD_KEYWORD_IN: + case MSH_LEXER_ITEM_TYPE_WORD_KEYWORD_ESAC: + case MSH_LEXER_ITEM_TYPE_WORD_KEYWORD_FOR: + case MSH_LEXER_ITEM_TYPE_WORD_KEYWORD_WHILE: + case MSH_LEXER_ITEM_TYPE_WORD_KEYWORD_UNTIL: + case MSH_LEXER_ITEM_TYPE_WORD_KEYWORD_DO: + case MSH_LEXER_ITEM_TYPE_WORD_KEYWORD_DONE: + msh_lexer_push_item(lexer, hash, cur_word_buf, *n); + break; + default: + msh_lexer_push_item(lexer, MSH_LEXER_ITEM_TYPE_WORD, cur_word_buf, *n); + break; + } + *n += 1; +}; + void msh_lexer_parse(msh_lexer *lexer, char *buf, SIZE_TYPE sz) { int i = 0, n = 0, j = 0; char cur_word_buf[1024]; @@ -94,8 +123,7 @@ void msh_lexer_parse(msh_lexer *lexer, char *buf, SIZE_TYPE sz) { char do_clear = 0; switch (buf[i]) { case '#': - cur_word_buf[n++] = '\0'; - msh_lexer_push_item(lexer, MSH_LEXER_ITEM_TYPE_WORD, cur_word_buf, n); + word_push(lexer, cur_word_buf, &n); goto lexer_cancel; case '\\': escaping = 1; @@ -125,8 +153,7 @@ void msh_lexer_parse(msh_lexer *lexer, char *buf, SIZE_TYPE sz) { /* fallthrough */ case '\n': case '\0': - cur_word_buf[n++] = '\0'; - msh_lexer_push_item(lexer, MSH_LEXER_ITEM_TYPE_WORD, cur_word_buf, n); + word_push(lexer, cur_word_buf, &n); do_clear = 1; break; default: diff --git a/src/lexer/lexer.h b/src/lexer/lexer.h index 232028b..075b9a5 100644 --- a/src/lexer/lexer.h +++ b/src/lexer/lexer.h @@ -41,6 +41,21 @@ typedef enum msh_lexer_item_type_t { MSH_LEXER_ITEM_TYPE_OP_PIPE, /* | */ MSH_LEXER_ITEM_TYPE_OP_CONTROL, /* & */ MSH_LEXER_ITEM_TYPE_OP_SEMICOLON, /* ; */ + + /* the keyword types have values corresponding to their string hash */ + MSH_LEXER_ITEM_TYPE_WORD_KEYWORD_IF = 177678, /* if */ + MSH_LEXER_ITEM_TYPE_WORD_KEYWORD_THEN = 193506854, /* then */ + MSH_LEXER_ITEM_TYPE_WORD_KEYWORD_ELSE = 193490665, /* else */ + MSH_LEXER_ITEM_TYPE_WORD_KEYWORD_ELIF = 193490655, /* elif */ + MSH_LEXER_ITEM_TYPE_WORD_KEYWORD_FI = 177675655, /* fi */ + MSH_LEXER_ITEM_TYPE_WORD_KEYWORD_CASE = 193488124, /* case */ + MSH_LEXER_ITEM_TYPE_WORD_KEYWORD_IN = 177678124, /* in */ + MSH_LEXER_ITEM_TYPE_WORD_KEYWORD_ESAC = 193490878, /* esac */ + MSH_LEXER_ITEM_TYPE_WORD_KEYWORD_FOR = 586338678, /* for */ + MSH_LEXER_ITEM_TYPE_WORD_KEYWORD_WHILE = 2090866937, /* while */ + MSH_LEXER_ITEM_TYPE_WORD_KEYWORD_UNTIL = 2090801957, /* until */ + MSH_LEXER_ITEM_TYPE_WORD_KEYWORD_DO = 1776731957, /* do */ + MSH_LEXER_ITEM_TYPE_WORD_KEYWORD_DONE = 1934896707, /* done */ } msh_lexer_item_type; typedef struct msh_lexer_item_t { diff --git a/src/main.c b/src/main.c index ee38242..7bd859e 100644 --- a/src/main.c +++ b/src/main.c @@ -29,6 +29,7 @@ */ #include "lexer/lexer.h" #include "system/system.h" +#include "util/util.h" static struct { msh_lexer lexer;