mirror of
https://github.com/Savapitech/42sh.git
synced 2026-01-18 16:57:28 +01:00
Add expr
Add expr
This commit is contained in:
1
Makefile
1
Makefile
@@ -13,6 +13,7 @@ LIB_NAME := libu.a
|
||||
|
||||
SRC := $(wildcard src/*.c)
|
||||
SRC += $(wildcard src/builtins/*.c)
|
||||
SRC += $(wildcard src/builtins/expr/*.c)
|
||||
SRC += $(wildcard src/ast/*.c)
|
||||
SRC += $(wildcard src/utils/*.c)
|
||||
SRC += $(wildcard src/local/*.c)
|
||||
|
||||
@@ -37,4 +37,5 @@ int builtins_unset(ef_t *ef, char **args);
|
||||
int builtins_where(ef_t *ef, char **args);
|
||||
int builtins_which(ef_t *ef, char **args);
|
||||
int builtins_break(ef_t *ef, char **args);
|
||||
int builtins_expr(ef_t *ef, char **args);
|
||||
#endif /* BUILTIND_H */
|
||||
|
||||
51
src/builtins/expr/expr.h
Normal file
51
src/builtins/expr/expr.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
** EPITECH PROJECT, 2025
|
||||
** __
|
||||
** File description:
|
||||
** _
|
||||
*/
|
||||
|
||||
#ifndef EXPR_H
|
||||
#define EXPR_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#define FIRST_TOKEN_BATCH_SIZE 64
|
||||
#define IS_CHAR(s, c) ((s)[0] == (c) && (s)[1] == '\0')
|
||||
|
||||
#define COUNT_OF(arr) (sizeof (arr) / (sizeof *(arr)))
|
||||
|
||||
typedef unsigned char uchar_t;
|
||||
|
||||
typedef enum {
|
||||
E_VAL_INT = 'd',
|
||||
E_VAL_STR = 's',
|
||||
E_VAL_ERR = 'e',
|
||||
} expr_val_type_t;
|
||||
|
||||
typedef struct {
|
||||
char *p;
|
||||
union {
|
||||
long val;
|
||||
char const *str;
|
||||
};
|
||||
char type;
|
||||
} expr_val_t;
|
||||
|
||||
typedef struct {
|
||||
char name[4];
|
||||
unsigned int prec;
|
||||
expr_val_t (*apply)(expr_val_t *, expr_val_t *);
|
||||
} expr_op_precedence_t;
|
||||
|
||||
typedef struct {
|
||||
char **args;
|
||||
} expr_state_t;
|
||||
|
||||
expr_val_t expr_run(expr_state_t *state, uchar_t depth, int prec);
|
||||
|
||||
extern const expr_op_precedence_t OPERATOR_PRECEDENCE[];
|
||||
extern const size_t OPERATOR_PRECEDENCE_COUNT;
|
||||
|
||||
#endif
|
||||
111
src/builtins/expr/expr_applicators.c
Normal file
111
src/builtins/expr/expr_applicators.c
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
** EPITECH PROJECT, 2025
|
||||
** __
|
||||
** File description:
|
||||
** _
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "expr.h"
|
||||
|
||||
static
|
||||
expr_val_t apply_add(expr_val_t *left, expr_val_t *right)
|
||||
{
|
||||
expr_val_t res;
|
||||
|
||||
if (left->type != E_VAL_INT || right->type != E_VAL_INT) {
|
||||
res.str = "non-integer argument";
|
||||
res.type = E_VAL_ERR;
|
||||
} else {
|
||||
res.val = left->val + right->val;
|
||||
res.type = E_VAL_INT;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static
|
||||
expr_val_t apply_sub(expr_val_t *left, expr_val_t *right)
|
||||
{
|
||||
expr_val_t res;
|
||||
|
||||
if (left->type != E_VAL_INT || right->type != E_VAL_INT) {
|
||||
res.str = "non-integer argument";
|
||||
res.type = E_VAL_ERR;
|
||||
} else {
|
||||
res.val = left->val - right->val;
|
||||
res.type = E_VAL_INT;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static
|
||||
expr_val_t apply_mul(expr_val_t *left, expr_val_t *right)
|
||||
{
|
||||
expr_val_t res;
|
||||
|
||||
if (left->type != E_VAL_INT || right->type != E_VAL_INT) {
|
||||
res.str = "non-integer argument";
|
||||
res.type = E_VAL_ERR;
|
||||
} else {
|
||||
res.val = left->val * right->val;
|
||||
res.type = E_VAL_INT;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static
|
||||
expr_val_t apply_div(expr_val_t *left, expr_val_t *right)
|
||||
{
|
||||
expr_val_t res = { .type = E_VAL_ERR };
|
||||
|
||||
if (left->type != E_VAL_INT || right->type != E_VAL_INT) {
|
||||
res.str = "non-integer argument";
|
||||
res.type = E_VAL_ERR;
|
||||
return res;
|
||||
}
|
||||
if (right->val == 0) {
|
||||
res.str = "division by zero";
|
||||
res.type = E_VAL_ERR;
|
||||
return res;
|
||||
}
|
||||
res.val = left->val / right->val;
|
||||
res.type = E_VAL_INT;
|
||||
return res;
|
||||
}
|
||||
|
||||
static
|
||||
expr_val_t apply_lt(expr_val_t *left, expr_val_t *right)
|
||||
{
|
||||
expr_val_t res = { .type = E_VAL_INT };
|
||||
|
||||
if (left->type == E_VAL_INT && right->type == E_VAL_INT)
|
||||
res.val = left->val < right->val;
|
||||
else
|
||||
res.val = strcmp(left->p, right->p) < 0;
|
||||
return res;
|
||||
}
|
||||
|
||||
static
|
||||
expr_val_t apply_gt(expr_val_t *left, expr_val_t *right)
|
||||
{
|
||||
expr_val_t res = { .type = E_VAL_INT };
|
||||
|
||||
if (left->type == E_VAL_INT && right->type == E_VAL_INT)
|
||||
res.val = left->val > right->val;
|
||||
else
|
||||
res.val = strcmp(left->p, right->p) > 0;
|
||||
return res;
|
||||
}
|
||||
|
||||
const expr_op_precedence_t OPERATOR_PRECEDENCE[] = {
|
||||
{ .name = "+", .prec = 2, apply_add },
|
||||
{ .name = "-", .prec = 2, apply_sub },
|
||||
{ .name = "*", .prec = 3, apply_mul },
|
||||
{ .name = "/", .prec = 3, apply_div },
|
||||
{ .name = "<", .prec = 1, apply_lt },
|
||||
{ .name = ">", .prec = 1, apply_gt },
|
||||
};
|
||||
|
||||
const size_t OPERATOR_PRECEDENCE_COUNT = COUNT_OF(OPERATOR_PRECEDENCE);
|
||||
100
src/builtins/expr/expr_eval.c
Normal file
100
src/builtins/expr/expr_eval.c
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
** EPITECH PROJECT, 2025
|
||||
** __
|
||||
** File description:
|
||||
** _
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "expr.h"
|
||||
|
||||
static
|
||||
const expr_op_precedence_t *op_precedence(char *op)
|
||||
{
|
||||
for (size_t i = 0; i < OPERATOR_PRECEDENCE_COUNT; i++)
|
||||
if (!strcmp(op, OPERATOR_PRECEDENCE[i].name))
|
||||
return OPERATOR_PRECEDENCE + i;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static
|
||||
expr_val_t expr_parse_paren(expr_state_t *state, uchar_t depth)
|
||||
{
|
||||
expr_val_t out;
|
||||
|
||||
state->args++;
|
||||
out = expr_run(state, depth, 0);
|
||||
if (out.type == E_VAL_ERR)
|
||||
return out;
|
||||
if (*state->args == NULL || !IS_CHAR(*state->args, ')')) {
|
||||
out.str = "syntax error: missing ')'";
|
||||
out.type = E_VAL_ERR;
|
||||
return out;
|
||||
}
|
||||
state->args++;
|
||||
return out;
|
||||
}
|
||||
|
||||
static
|
||||
void expr_solve_precedence(
|
||||
expr_val_t *out,
|
||||
expr_state_t *state, uchar_t depth, unsigned int prec)
|
||||
{
|
||||
const expr_op_precedence_t *op_prec;
|
||||
expr_val_t tmp;
|
||||
|
||||
while (*state->args != NULL && !IS_CHAR(*state->args, ')')) {
|
||||
op_prec = op_precedence(*state->args);
|
||||
if (op_prec == NULL) {
|
||||
out->type = E_VAL_ERR;
|
||||
out->str = "syntax error: unexpected argument";
|
||||
break;
|
||||
}
|
||||
if (op_prec->prec == 0 || op_prec->prec <= prec)
|
||||
return;
|
||||
state->args++;
|
||||
tmp = expr_run(state, depth, op_prec->prec);
|
||||
if (tmp.type == E_VAL_ERR) {
|
||||
*out = tmp;
|
||||
break;
|
||||
}
|
||||
*out = op_prec->apply(out, &tmp);
|
||||
}
|
||||
}
|
||||
|
||||
expr_val_t expr_parse_val(expr_state_t *state)
|
||||
{
|
||||
expr_val_t out;
|
||||
char *chk;
|
||||
|
||||
out.val = strtol(*state->args, &chk, 10);
|
||||
out.p = *state->args;
|
||||
if (chk != *state->args && *chk == '\0')
|
||||
out.type = E_VAL_INT;
|
||||
else
|
||||
out.type = E_VAL_STR;
|
||||
state->args++;
|
||||
return out;
|
||||
}
|
||||
|
||||
expr_val_t expr_run(expr_state_t *state, uchar_t depth, int prec)
|
||||
{
|
||||
expr_val_t out = {
|
||||
.type = E_VAL_ERR,
|
||||
.str = "syntax error: missing argument"
|
||||
};
|
||||
|
||||
if (*state->args == NULL)
|
||||
return out;
|
||||
if (IS_CHAR(*state->args, '('))
|
||||
out = expr_parse_paren(state, depth + 1);
|
||||
else
|
||||
out = expr_parse_val(state);
|
||||
expr_solve_precedence(&out, state, depth, prec);
|
||||
return out;
|
||||
}
|
||||
37
src/builtins/expr/expr_main.c
Normal file
37
src/builtins/expr/expr_main.c
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
** EPITECH PROJECT, 2025
|
||||
** __
|
||||
** File description:
|
||||
** _
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "exec.h"
|
||||
#include "expr.h"
|
||||
|
||||
int builtins_expr(ef_t *ef, char **args)
|
||||
{
|
||||
int argc = 0;
|
||||
expr_state_t state;
|
||||
expr_val_t ret;
|
||||
|
||||
for (; args[argc] != NULL; argc++);
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "expr: missing operand\n");
|
||||
return RETURN_FAILURE;
|
||||
}
|
||||
state = (expr_state_t){ .args = &args[1] };
|
||||
ret = expr_run(&state, 0, 0);
|
||||
if (ret.type == E_VAL_ERR) {
|
||||
printf("expr: %s\n", ret.str);
|
||||
return RETURN_FAILURE;
|
||||
}
|
||||
if (ret.type == E_VAL_INT)
|
||||
printf("%ld\n", ret.val);
|
||||
if (ret.type == E_VAL_STR)
|
||||
printf("%s\n", ret.p);
|
||||
return RETURN_SUCCESS;
|
||||
}
|
||||
@@ -44,6 +44,7 @@ const builtins_funcs_t BUILTINS[] = {
|
||||
{ "unset", &builtins_unset },
|
||||
{ "where", &builtins_where },
|
||||
{ "which", &builtins_which },
|
||||
{ "expr", &builtins_expr },
|
||||
{ "break", &builtins_break }
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user