diff options
| author | Martial Simon <msimon_fr@hotmail.com> | 2025-09-15 01:07:58 +0200 |
|---|---|---|
| committer | Martial Simon <msimon_fr@hotmail.com> | 2025-09-15 01:07:58 +0200 |
| commit | 967be9e750221ab2ab783f95df79bb26d290a45e (patch) | |
| tree | 6802900a5e975f9f68b169f0f503f040056d6952 /21sh | |
Diffstat (limited to '21sh')
28 files changed, 866 insertions, 0 deletions
diff --git a/21sh/autotools/.gitignore b/21sh/autotools/.gitignore new file mode 100644 index 0000000..89511ec --- /dev/null +++ b/21sh/autotools/.gitignore @@ -0,0 +1,54 @@ +# http://www.gnu.org/software/automake + +Makefile.in +COPYING +INSTALL +/ar-lib +/mdate-sh +/py-compile +/test-driver +/ylwrap +.deps/ +.dirstamp + +# http://www.gnu.org/software/autoconf + +autom4te.cache +/autoscan.log +/autoscan-*.log +/aclocal.m4 +/compile +/config.cache +/config.guess +/config.h.in +/config.log +/config.status +/config.sub +/configure +/configure.scan +/depcomp +/install-sh +/missing +/stamp-h1 + +# https://www.gnu.org/software/libtool/ + +/ltmain.sh + +# http://www.gnu.org/software/texinfo + +/texinfo.tex + +# http://www.gnu.org/software/m4/ + +m4/libtool.m4 +m4/ltoptions.m4 +m4/ltsugar.m4 +m4/ltversion.m4 +m4/lt~obsolete.m4 + +# Generated Makefile +# (meta build system like autotools, +# can automatically generate from config.status script +# (which is called by configure script)) +Makefile diff --git a/21sh/autotools/Makefile.am b/21sh/autotools/Makefile.am new file mode 100644 index 0000000..af437a6 --- /dev/null +++ b/21sh/autotools/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = src diff --git a/21sh/autotools/configure.ac b/21sh/autotools/configure.ac new file mode 100644 index 0000000..e3a60b6 --- /dev/null +++ b/21sh/autotools/configure.ac @@ -0,0 +1,14 @@ +AC_INIT([autotools], [0.1], [martial.simon@epita.fr]) +AM_INIT_AUTOMAKE([subdir-objects] [foreign]) +AC_PROG_RANLIB +AM_PROG_AR +AC_PROG_CC +AX_COMPILER_FLAGS([], [], [], [-Wall -Wextra -Werror -Wvla -pedantic -std=c99]) +AC_CONFIG_FILES([ + Makefile + src/Makefile + src/ast/Makefile + src/lexer/Makefile + src/parser/Makefile + ]) +AC_OUTPUT diff --git a/21sh/autotools/src/42sh.c b/21sh/autotools/src/42sh.c new file mode 100644 index 0000000..cb3f00b --- /dev/null +++ b/21sh/autotools/src/42sh.c @@ -0,0 +1,7 @@ +#include "ast/ast.h" + +int main(void) +{ + print_ast(); + return 0; +} diff --git a/21sh/autotools/src/Makefile.am b/21sh/autotools/src/Makefile.am new file mode 100644 index 0000000..6a2c6ae --- /dev/null +++ b/21sh/autotools/src/Makefile.am @@ -0,0 +1,7 @@ +SUBDIRS = ast lexer parser + +bin_PROGRAMS = 42sh +42sh_SOURCES = 42sh.c +42sh_CPPFLAGS = -I%D% +42sh_CFLAGS = -std=c99 -Werror -Wall -Wextra -Wvla -pedantic +42sh_LDADD = ast/libast.a lexer/liblexer.a parser/libparser.a diff --git a/21sh/autotools/src/ast/Makefile.am b/21sh/autotools/src/ast/Makefile.am new file mode 100644 index 0000000..d455958 --- /dev/null +++ b/21sh/autotools/src/ast/Makefile.am @@ -0,0 +1,6 @@ +lib_LIBRARIES = libast.a + +libast_a_SOURCES = ast.c ast.h +libast_a_CPPFLAGS = -I$(top_srcdir)/src +libast_a_CFLAGS = -std=c99 -Werror -Wall -Wextra -Wvla -pedantic +noinst_LIBRARIES = libast.a diff --git a/21sh/autotools/src/ast/ast.c b/21sh/autotools/src/ast/ast.c new file mode 100644 index 0000000..084dbf9 --- /dev/null +++ b/21sh/autotools/src/ast/ast.c @@ -0,0 +1,11 @@ +#include "ast.h" + +#include <stdio.h> + +#include "parser/parser.h" + +void print_ast() +{ + printf("ast !!!\n"); + print_parser(); +} diff --git a/21sh/autotools/src/ast/ast.h b/21sh/autotools/src/ast/ast.h new file mode 100644 index 0000000..83d52b3 --- /dev/null +++ b/21sh/autotools/src/ast/ast.h @@ -0,0 +1,6 @@ +#ifndef AST_H +#define AST_H + +void print_ast(); + +#endif /* ! AST_H */ diff --git a/21sh/autotools/src/lexer/Makefile.am b/21sh/autotools/src/lexer/Makefile.am new file mode 100644 index 0000000..f5f78b2 --- /dev/null +++ b/21sh/autotools/src/lexer/Makefile.am @@ -0,0 +1,6 @@ +lib_LIBRARIES = liblexer.a + +liblexer_a_SOURCES = lexer.c lexer.h +liblexer_a_CPPFLAGS = -I$(top_srcdir)/src +liblexer_a_CFLAGS = -std=c99 -Werror -Wall -Wextra -Wvla -pedantic +noinst_LIBRARIES = liblexer.a diff --git a/21sh/autotools/src/lexer/lexer.c b/21sh/autotools/src/lexer/lexer.c new file mode 100644 index 0000000..2e9d2f9 --- /dev/null +++ b/21sh/autotools/src/lexer/lexer.c @@ -0,0 +1,8 @@ +#include "lexer.h" + +#include <stdio.h> + +void print_lexer() +{ + puts("Vive les lexer"); +} diff --git a/21sh/autotools/src/lexer/lexer.h b/21sh/autotools/src/lexer/lexer.h new file mode 100644 index 0000000..0cc2c2e --- /dev/null +++ b/21sh/autotools/src/lexer/lexer.h @@ -0,0 +1,6 @@ +#ifndef LEXER_H +#define LEXER_H + +void print_lexer(); + +#endif /* ! LEXER_H */ diff --git a/21sh/autotools/src/parser/Makefile.am b/21sh/autotools/src/parser/Makefile.am new file mode 100644 index 0000000..c8fe590 --- /dev/null +++ b/21sh/autotools/src/parser/Makefile.am @@ -0,0 +1,6 @@ +lib_LIBRARIES = libparser.a + +libparser_a_SOURCES = parser.c parser.h $(top_srcdir)/src/lexer/lexer.c $(top_srcdir)/src/lexer/lexer.h +libparser_a_CPPFLAGS = -I$(top_srcdir)/src +libparser_a_CFLAGS = -std=c99 -Werror -Wall -Wextra -Wvla -pedantic +noinst_LIBRARIES = libparser.a diff --git a/21sh/autotools/src/parser/parser.c b/21sh/autotools/src/parser/parser.c new file mode 100644 index 0000000..28f5824 --- /dev/null +++ b/21sh/autotools/src/parser/parser.c @@ -0,0 +1,11 @@ +#include "parser.h" + +#include <stdio.h> + +#include "lexer/lexer.h" + +void print_parser() +{ + print_lexer(); + printf("parser !!!\n"); +} diff --git a/21sh/autotools/src/parser/parser.h b/21sh/autotools/src/parser/parser.h new file mode 100644 index 0000000..38d2ae3 --- /dev/null +++ b/21sh/autotools/src/parser/parser.h @@ -0,0 +1,6 @@ +#ifndef PARSER_H +#define PARSER_H + +void print_parser(); + +#endif /* ! PARSER_H */ diff --git a/21sh/ll-expr/Makefile b/21sh/ll-expr/Makefile new file mode 100644 index 0000000..0293956 --- /dev/null +++ b/21sh/ll-expr/Makefile @@ -0,0 +1,27 @@ +CC = gcc +CFLAGS = -Wall -Werror -Wextra -std=c99 -pedantic -Wvla -fsanitize=address +CPPFLAGS = -Isrc -Isrc/parser -Isrc/lexer -Isrc/ast +LDFLAGS = -fsanitize=address + +OBJS = src/ast/ast.o \ + src/lexer/lexer.o \ + src/parser/parser.o + +OBJ_AST = src/eval/ast_print.o +OBJ_RPN = src/eval/rpn_print.o +OBJ_TOKEN = src/eval/token_printer.o + +all: ast rpn token + +ast: $(OBJS) $(OBJ_AST) + $(CC) $(LDFLAGS) -o eval_ast $(OBJS) $(OBJ_AST) + +rpn: $(OBJS) $(OBJ_RPN) + $(CC) $(LDFLAGS) -o eval_rpn $(OBJS) $(OBJ_RPN) + +token: $(OBJS) $(OBJ_TOKEN) + $(CC) $(LDFLAGS) -o eval_token $(OBJS) $(OBJ_TOKEN) + +clean: + $(RM) $(OBJS) $(OBJ_AST) $(OBJ_TOKEN) $(OBJ_RPN) eval_* + diff --git a/21sh/ll-expr/src/ast/ast.c b/21sh/ll-expr/src/ast/ast.c new file mode 100644 index 0000000..701d40e --- /dev/null +++ b/21sh/ll-expr/src/ast/ast.c @@ -0,0 +1,27 @@ +#include "ast.h" + +#include <err.h> +#include <stdlib.h> + +struct ast *ast_new(enum ast_type type) +{ + struct ast *new = calloc(1, sizeof(struct ast)); + if (!new) + return NULL; + new->type = type; + return new; +} + +void ast_free(struct ast *ast) +{ + if (ast == NULL) + return; + + ast_free(ast->left); + ast->left = NULL; + + ast_free(ast->right); + ast->right = NULL; + + free(ast); +} diff --git a/21sh/ll-expr/src/ast/ast.h b/21sh/ll-expr/src/ast/ast.h new file mode 100644 index 0000000..01e0064 --- /dev/null +++ b/21sh/ll-expr/src/ast/ast.h @@ -0,0 +1,40 @@ +#ifndef AST_H +#define AST_H + +#include <unistd.h> + +enum ast_type +{ + AST_PLUS, + AST_MINUS, + AST_MUL, + AST_DIV, + AST_NUMBER, + AST_NEG +}; + +/** + * This very simple AST structure should be sufficient for a simple AST. + * It is however, NOT GOOD ENOUGH for more complicated projects, such as a + * shell. Please read the project guide for some insights about other kinds of + * ASTs. + */ +struct ast +{ + enum ast_type type; // The kind of node we're dealing with + ssize_t value; // If the node is a number, it stores its value + struct ast *left; // The left branch if any, unary or binary + struct ast *right; // The right branch of the binary node +}; + +/** + ** \brief Allocates a new ast with the given type. + */ +struct ast *ast_new(enum ast_type type); + +/** + ** \brief Recursively frees the given ast. + */ +void ast_free(struct ast *ast); + +#endif /* !AST_H */ diff --git a/21sh/ll-expr/src/eval/ast_print.c b/21sh/ll-expr/src/eval/ast_print.c new file mode 100644 index 0000000..9d7cbb8 --- /dev/null +++ b/21sh/ll-expr/src/eval/ast_print.c @@ -0,0 +1,57 @@ +#include <stdio.h> + +#include "lexer.h" +#include "parser.h" + +char tab[] = { [AST_PLUS] = '+', + [AST_MINUS] = '-', + [AST_MUL] = '*', + [AST_DIV] = '/' }; + +void print_ast(struct ast *ast) +{ + if (ast == NULL) + return; + + if (ast->type == AST_NUMBER) + printf("%zu", ast->value); + else if (ast->type == AST_NEG) + printf("-%zu", (ast->left)->value); + else + { + printf("("); + + print_ast(ast->left); + + printf("%c", tab[ast->type]); + + print_ast(ast->right); + + printf(")"); + } +} + +int main(int argc, char *argv[]) +{ + if (argc != 2) + return 1; + + struct lexer *lexer = lexer_new(argv[1]); + + struct ast *ast; + enum parser_status status = PARSER_OK; + ast = parse(&status, lexer); + if (status != PARSER_OK) + { + lexer_free(lexer); + return 1; + } + + print_ast(ast); + printf("\n"); + + ast_free(ast); + lexer_free(lexer); + + return 0; +} diff --git a/21sh/ll-expr/src/eval/rpn_print.c b/21sh/ll-expr/src/eval/rpn_print.c new file mode 100644 index 0000000..defb519 --- /dev/null +++ b/21sh/ll-expr/src/eval/rpn_print.c @@ -0,0 +1,52 @@ +#include <stdio.h> + +#include "lexer.h" +#include "parser.h" + +char tab[] = { [AST_PLUS] = '+', + [AST_MINUS] = '-', + [AST_MUL] = '*', + [AST_DIV] = '/' }; + +void print_ast(struct ast *ast) +{ + if (!ast) + return; + + if (ast->type == AST_NUMBER) + printf("%zu ", ast->value); + else if (ast->type == AST_NEG) + printf("-%zu ", (ast->left)->value); + else + { + print_ast(ast->left); + print_ast(ast->right); + + printf("%c ", tab[ast->type]); + } +} + +int main(int argc, char *argv[]) +{ + if (argc != 2) + return 1; + + struct lexer *lexer = lexer_new(argv[1]); + + struct ast *ast; + enum parser_status status; + ast = parse(&status, lexer); + if (status != PARSER_OK) + { + lexer_free(lexer); + return 1; + } + + print_ast(ast); + printf("\n"); + + ast_free(ast); + lexer_free(lexer); + + return 0; +} diff --git a/21sh/ll-expr/src/eval/token_printer.c b/21sh/ll-expr/src/eval/token_printer.c new file mode 100644 index 0000000..78096f4 --- /dev/null +++ b/21sh/ll-expr/src/eval/token_printer.c @@ -0,0 +1,34 @@ +#include <stdio.h> + +#include "lexer.h" + +char tab[] = { + [TOKEN_PLUS] = '+', [TOKEN_MINUS] = '-', [TOKEN_MUL] = '*', + [TOKEN_DIV] = '/', [TOKEN_LEFT_PAR] = '(', [TOKEN_RIGHT_PAR] = ')' +}; + +int main(int argc, char *argv[]) +{ + if (argc != 2) + return 1; + + struct lexer *lexer = lexer_new(argv[1]); + struct token token = lexer_pop(lexer); + + while (token.type != TOKEN_EOF && token.type != TOKEN_ERROR) + { + if (token.type == TOKEN_NUMBER) + printf("%zu\n", token.value); + else + printf("%c\n", tab[token.type]); + + token = lexer_pop(lexer); + } + + if (token.type == TOKEN_EOF) + printf("EOF\n"); + + lexer_free(lexer); + + return 0; +} diff --git a/21sh/ll-expr/src/lexer/lexer.c b/21sh/ll-expr/src/lexer/lexer.c new file mode 100644 index 0000000..3b3d29f --- /dev/null +++ b/21sh/ll-expr/src/lexer/lexer.c @@ -0,0 +1,104 @@ +#include "lexer.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +struct lexer *lexer_new(const char *input) +{ + struct lexer *new = malloc(sizeof(struct lexer)); + new->input = input; + new->pos = 0; + return new; +} + +void lexer_free(struct lexer *lexer) +{ + free(lexer); +} + +struct template +{ + char value; + enum token_type type; +}; + +struct template templates[] = { + { '+', TOKEN_PLUS }, { '-', TOKEN_MINUS }, { '*', TOKEN_MUL }, + { '/', TOKEN_DIV }, { '(', TOKEN_LEFT_PAR }, { ')', TOKEN_RIGHT_PAR }, + { '\0', TOKEN_EOF }, { 0, TOKEN_ERROR } +}; + +static ssize_t parse_number(struct lexer *l) +{ + union + { + const char *cc; + char *c; + } cast; + cast.cc = l->input + l->pos; + char *in = cast.c; + size_t t = 0; + while (in[t] && in[t] >= '0' && in[t] <= '9') + t++; + char tmp = in[t]; + in[t] = '\0'; + ssize_t res = atoi(in); + in[t] = tmp; + return res; +} + +struct token lexer_next_token(struct lexer *lexer) +{ + for (; lexer->input[lexer->pos] && lexer->input[lexer->pos] == ' '; + lexer->pos++) + continue; + for (int i = 0; i < 7; i++) + { + if (lexer->input[lexer->pos] == templates[i].value) + { + lexer->current_tok.type = templates[i].type; + return lexer->current_tok; + } + } + if (lexer->input[lexer->pos] > '9' || lexer->input[lexer->pos] < '0') + { + lexer->current_tok.type = TOKEN_ERROR; + fprintf(stderr, "lexer: invalid token %c\n", lexer->input[lexer->pos]); + return lexer->current_tok; + } + else + { + lexer->current_tok.type = TOKEN_NUMBER; + lexer->current_tok.value = parse_number(lexer); + return lexer->current_tok; + } +} + +struct token lexer_peek(struct lexer *lexer) +{ + return lexer_next_token(lexer); +} + +static size_t count_numbers(ssize_t value) +{ + if (value == 0) + return 1; + size_t size = 0; + while (value) + { + size++; + value /= 10; + } + return size; +} + +struct token lexer_pop(struct lexer *lexer) +{ + struct token res = lexer_next_token(lexer); + if (res.type == TOKEN_NUMBER) + lexer->pos += count_numbers(res.value); + else + lexer->pos++; + return res; +} diff --git a/21sh/ll-expr/src/lexer/lexer.h b/21sh/ll-expr/src/lexer/lexer.h new file mode 100644 index 0000000..40a7cc9 --- /dev/null +++ b/21sh/ll-expr/src/lexer/lexer.h @@ -0,0 +1,61 @@ +#ifndef LEXER_H +#define LEXER_H + +#include "token.h" + +/** + * \page Lexer + * + * The lexer cuts some input text into blocks called tokens. + + * This process is done **on demand**: the lexer doesn't read the + * input more than it needs, only creates tokens when lexer_peek + * or lexer_pop is called, and no token is available. + * + * "2 + 3" will produce 3 tokens: + * - TOKEN_NUMBER { .value = 2 } + * - TOKEN_PLUS + * - TOKEN_NUMBER { .value = 3 } + */ + +struct lexer +{ + const char *input; // The input data + size_t pos; // The current offset inside the input data + struct token current_tok; // The next token, if processed +}; + +/** + * \brief Creates a new lexer given an input string. + */ +struct lexer *lexer_new(const char *input); + +/** + ** \brief Frees the given lexer, but not its input. + */ +void lexer_free(struct lexer *lexer); + +/** + * \brief Returns a token from the input string. + + * This function goes through the input string character by character and + * builds a token. lexer_peek and lexer_pop should call it. If the input is + * invalid, you must print something on stderr and return the appropriate token. + */ +struct token lexer_next_token(struct lexer *lexer); + +/** + * \brief Returns the next token, but doesn't move forward: calling lexer_peek + * multiple times in a row always returns the same result. + * This function is meant to help the parser check if the next token matches + * some rule. + */ +struct token lexer_peek(struct lexer *lexer); + +/** + * \brief Returns the next token, and removes it from the stream: + * calling lexer_pop in a loop will iterate over all tokens until EOF. + */ +struct token lexer_pop(struct lexer *lexer); + +#endif /* !LEXER_H */ diff --git a/21sh/ll-expr/src/lexer/token.h b/21sh/ll-expr/src/lexer/token.h new file mode 100644 index 0000000..b0866fc --- /dev/null +++ b/21sh/ll-expr/src/lexer/token.h @@ -0,0 +1,25 @@ +#ifndef TOKEN_H +#define TOKEN_H + +#include <unistd.h> + +enum token_type +{ + TOKEN_PLUS, // '+' + TOKEN_MINUS, // '-' + TOKEN_MUL, // '*' + TOKEN_DIV, // '/' + TOKEN_NUMBER, // "[0-9]+" + TOKEN_LEFT_PAR, // '(' + TOKEN_RIGHT_PAR, // ')' + TOKEN_EOF, // end of input marker + TOKEN_ERROR // it is not a real token, it is returned in case of invalid + // input +}; + +struct token +{ + enum token_type type; // The kind of token + ssize_t value; // If the token is a number, its value +}; +#endif /* !TOKEN_H */ diff --git a/21sh/ll-expr/src/parser/parser.c b/21sh/ll-expr/src/parser/parser.c new file mode 100644 index 0000000..d1a1526 --- /dev/null +++ b/21sh/ll-expr/src/parser/parser.c @@ -0,0 +1,149 @@ +#include "parser.h" + +#include <stdio.h> + +struct ast *parse(enum parser_status *status, struct lexer *lexer) +{ + struct token t = lexer_peek(lexer); + *status = PARSER_OK; + if (t.type == TOKEN_EOF) + { + lexer_pop(lexer); + return NULL; + } + else + { + struct ast *exp = parse_exp(status, lexer); + if (*status != PARSER_OK) + { + return NULL; + } + struct token t = lexer_pop(lexer); + if (*status == PARSER_OK && t.type == TOKEN_EOF) + { + return exp; + } + else if (t.type != TOKEN_EOF) + { + *status = PARSER_UNEXPECTED_TOKEN; + fprintf(stderr, "parser: unexpected token\n"); + } + ast_free(exp); + return NULL; + } +} + +struct ast *parse_exp(enum parser_status *status, struct lexer *lexer) +{ + struct ast *left = parse_sexp(status, lexer); + if (*status == PARSER_UNEXPECTED_TOKEN) + return NULL; + struct token t = lexer_peek(lexer); + if (t.type != TOKEN_PLUS && t.type != TOKEN_MINUS) + { + *status = PARSER_OK; + return left; + } + else + { + struct ast *root = left; + do + { + left = root; + t = lexer_pop(lexer); + if (t.type == TOKEN_PLUS) + root = ast_new(AST_PLUS); + else + root = ast_new(AST_MINUS); + root->left = left; + root->right = parse_sexp(status, lexer); + if (*status == PARSER_UNEXPECTED_TOKEN) + { + ast_free(root); + return NULL; + } + t = lexer_peek(lexer); + } while (t.type != TOKEN_EOF + && (t.type == TOKEN_PLUS || t.type == TOKEN_MINUS)); + return root; + } +} + +struct ast *parse_sexp(enum parser_status *status, struct lexer *lexer) +{ + struct ast *left = parse_texp(status, lexer); + if (*status == PARSER_UNEXPECTED_TOKEN) + return NULL; + struct token t = lexer_peek(lexer); + if (t.type != TOKEN_MUL && t.type != TOKEN_DIV) + { + *status = PARSER_OK; + return left; + } + else + { + struct ast *root = left; + do + { + left = root; + t = lexer_pop(lexer); + if (t.type == TOKEN_MUL) + root = ast_new(AST_MUL); + else + root = ast_new(AST_DIV); + root->left = left; + root->right = parse_texp(status, lexer); + if (*status == PARSER_UNEXPECTED_TOKEN) + { + ast_free(root); + return NULL; + } + t = lexer_peek(lexer); + } while (t.type != TOKEN_EOF + && (t.type == TOKEN_MUL || t.type == TOKEN_DIV)); + return root; + } +} + +struct ast *parse_texp(enum parser_status *status, struct lexer *lexer) +{ + struct token t = lexer_pop(lexer); + if (t.type == TOKEN_NUMBER) + { + struct ast *res = ast_new(AST_NUMBER); + res->value = t.value; + return res; + } + else if (t.type == TOKEN_MINUS) + { + t = lexer_peek(lexer); + if (t.type != TOKEN_NUMBER && t.type != TOKEN_LEFT_PAR) + { + *status = PARSER_UNEXPECTED_TOKEN; + fprintf(stderr, "parser: unexpected token\n"); + return NULL; + } + struct ast *unary = ast_new(AST_NEG); + unary->left = parse_texp(status, lexer); + return unary; + } + else if (t.type == TOKEN_LEFT_PAR) + { + struct ast *exp = parse_exp(status, lexer); + t = lexer_pop(lexer); + if (t.type != TOKEN_RIGHT_PAR) + { + *status = PARSER_UNEXPECTED_TOKEN; + fprintf(stderr, "parser: expected closing parenthesis\n"); + ast_free(exp); + return NULL; + } + return exp; + } + else + { + *status = PARSER_UNEXPECTED_TOKEN; + fprintf(stderr, "parser: unexpected token\n"); + return NULL; + } +} diff --git a/21sh/ll-expr/src/parser/parser.h b/21sh/ll-expr/src/parser/parser.h new file mode 100644 index 0000000..057c6bc --- /dev/null +++ b/21sh/ll-expr/src/parser/parser.h @@ -0,0 +1,46 @@ +#ifndef PARSER_H +#define PARSER_H + +#include "ast.h" +#include "lexer.h" + +enum parser_status +{ + PARSER_OK, + PARSER_UNEXPECTED_TOKEN, +}; + +/** + * \brief Parses an expression or nothing. + * + * input = EOF + * | exp EOF ; + */ +struct ast *parse(enum parser_status *status, struct lexer *lexer); + +/** + * \brief Parses sexp expressions separated by + and -. + * + * exp = sexp { ( '+' | '-' ) sexp } ; + */ +struct ast *parse_exp(enum parser_status *status, struct lexer *lexer); + +/** + * \brief Parses texp expressions separated by * and /. + * + * sexp = texp { ('*' | '/' ) texp } ; + */ +struct ast *parse_sexp(enum parser_status *status, struct lexer *lexer); + +/** + * \brief Parses a number, a - a number, or a parenthesized expression. + * + * texp = NUMBER + * | '-' NUMBER + * | '-' '(' exp ')' + * | '(' exp ')' + * ; + */ +struct ast *parse_texp(enum parser_status *status, struct lexer *lexer); + +#endif /* !PARSER_H */ diff --git a/21sh/mypipe/mypipe.c b/21sh/mypipe/mypipe.c new file mode 100644 index 0000000..c019e42 --- /dev/null +++ b/21sh/mypipe/mypipe.c @@ -0,0 +1,43 @@ +#include "mypipe.h" + +#include <fcntl.h> +#include <unistd.h> + +int exec_pipe(char **argv_left, char **argv_right) +{ + int fds[2]; + if (pipe(fds)) + return 1; + pid_t pid = fork(); + if (pid == 0) + { + // close read end + close(fds[0]); + // redirect stdout to write end + dup2(fds[1], STDOUT_FILENO); + // tell OS to close write end after exec + fcntl(fds[1], F_SETFD, FD_CLOEXEC); + // exec left + execvp(argv_left[0], argv_left); + return 0; + } + else if (pid > 0) + { + // close write end + close(fds[1]); + // redirect stdin to read end + dup2(fds[0], STDIN_FILENO); + // tell OS to close read end after exec + fcntl(fds[0], F_SETFD, FD_CLOEXEC); + // exec right + execvp(argv_right[0], argv_right); + // return 1 + return 1; + } + else + { + close(fds[0]); + close(fds[1]); + return 1; + } +} diff --git a/21sh/mypipe/mypipe.h b/21sh/mypipe/mypipe.h new file mode 100644 index 0000000..d8c14e4 --- /dev/null +++ b/21sh/mypipe/mypipe.h @@ -0,0 +1,6 @@ +#ifndef MYPIPE_H +#define MYPIPE_H + +int exec_pipe(char **argv_left, char **argv_right); + +#endif /* ! MYPIPE_H */ diff --git a/21sh/myredir/myredir.c b/21sh/myredir/myredir.c new file mode 100644 index 0000000..071a8bf --- /dev/null +++ b/21sh/myredir/myredir.c @@ -0,0 +1,46 @@ +#include <err.h> +#include <fcntl.h> +#include <stdio.h> +#include <sys/wait.h> +#include <unistd.h> + +int main(int argc, char *argv[]) +{ + if (argc < 3) + { + fprintf(stderr, "Missing argument\n"); + return 2; + } + // Save stdout + int stdout_dup = dup(STDOUT_FILENO); + + int file_fd = open(argv[1], O_CREAT | O_WRONLY, 0644); + + // Redirect stdout to the file + dup2(file_fd, STDOUT_FILENO); + + int status; + + pid_t pid = fork(); + if (pid == 0) + { + execvp(argv[2], argv + 2); + return 127; + } + else + { + waitpid(pid, &status, 0); + if (WIFEXITED(status)) + { + status = WEXITSTATUS(status); + fflush(stdout); + dup2(stdout_dup, STDOUT_FILENO); + close(stdout_dup); + } + if (status != 127) + printf("%s exited with %d!\n", argv[2], status); + else + fprintf(stderr, "Missing command\n"); + return status == 127; + } +} |
