#include <stdio.h> #include <string.h> typedef unsigned char bool; /* Real type */ typedef unsigned int uint32_t; /* Real type, normally in <stdint.h>, a good practice to use it */ typedef enum { TOKEN_EAT, TOKEN_DQ, TOKEN_SQ, TOKEN_SEMI, TOKEN_DBL_SEMI, TOKEN_OPERATOR, TOKEN_NEG, TOKEN_DBLAND, TOKEN_DBLOR, TOKEN_PIPE, TOKEN_OP_ARITHM, TOKEN_AND, TOKEN_OP_BRA, TOKEN_CL_BRA, TOKEN_OP_PAR, TOKEN_CL_PAR, TOKEN_REDIR, TOKEN_ASS_WORD, TOKEN_OP_CMD, TOKEN_OP_CURLY, TOKEN_CL_CURLY, TOKEN_EQUAL, TOKEN_STRING, TOKEN_NAME, TOKEN_FOR, TOKEN_WHILE, TOKEN_NULL } e_token_type; typedef struct { const char* op; uint32_t size; e_token_type type; } t_oplist; typedef struct { char content[128]; /* Replace with a dynamic array */ uint32_t size; e_token_type type; } t_lexer_token; typedef struct { t_lexer_token tokens[2048]; /* Replace with a dynamic array */ uint32_t size; } t_lexer; static const t_oplist existing_token[] = { {"while", 5, TOKEN_WHILE}, /* Sort by size, for obvious reason ! */ {"$((", 3, TOKEN_OP_ARITHM}, {">>-", 3, TOKEN_REDIR}, {"for", 3, TOKEN_FOR}, {"$(", 2, TOKEN_OP_CMD}, {"${", 2, TOKEN_OP_CURLY}, {">>", 2, TOKEN_REDIR}, {"<<", 2, TOKEN_REDIR}, {"||", 2, TOKEN_DBLOR}, {">|", 2, TOKEN_REDIR}, {"<>", 2, TOKEN_REDIR}, {"<&", 2, TOKEN_REDIR}, {">&", 2, TOKEN_REDIR}, {"&&", 2, TOKEN_DBLAND}, {"{ ", 2, TOKEN_OP_BRA}, {"{\n", 2, TOKEN_OP_BRA}, {"{\v", 2, TOKEN_OP_BRA}, {"{\t", 2, TOKEN_OP_BRA}, {"{\r", 2, TOKEN_OP_BRA}, {"{\f", 2, TOKEN_OP_BRA}, {" {", 2, TOKEN_CL_BRA}, {"\n{", 2, TOKEN_CL_BRA}, {"\v{", 2, TOKEN_CL_BRA}, {"\t{", 2, TOKEN_CL_BRA}, {"\r{", 2, TOKEN_CL_BRA}, {"\f{", 2, TOKEN_CL_BRA}, {"))", 2, TOKEN_TOKEN}, {";;", 2, TOKEN_DBL_SEMI}, {"! ", 2, TOKEN_NEG}, {"}", 1, TOKEN_CL_BRA}, {"|", 1, TOKEN_PIPE}, {"&", 1, TOKEN_AND}, {"(", 1, TOKEN_OP_PAR}, {")", 1, TOKEN_CL_PAR}, {">", 1, TOKEN_REDIR}, {"<", 1, TOKEN_REDIR}, {"(", 1, TOKEN_OP_PAR}, {")", 1, TOKEN_CL_PAR}, {"{", 1, TOKEN_OP_CURLY}, {"}", 1, TOKEN_CL_CURLY}, {";", 1, TOKEN_SEMI}, {" ", 1, TOKEN_EAT}, {"\n", 1, TOKEN_EAT}, {"\v", 1, TOKEN_EAT}, {"\t", 1, TOKEN_EAT}, {"\r", 1, TOKEN_EAT}, {"\f", 1, TOKEN_EAT}, {"=", 1, TOKEN_EQUAL}, {NULL, 1, 0} }; void addToLexer(t_lexer* lexer, const char* text, uint32_t text_size, e_token_type type) { t_lexer_token item; strncpy(item.content, text, text_size); item.content[text_size] = 0; item.size = text_size; item.type = type; lexer->tokens[lexer->size] = item; ++lexer->size; } t_oplist searchTokenType(const char* s) { const t_oplist* ex_tok = existing_token; t_oplist not_found = {0, 0, 0}; while (ex_tok && ex_tok->op) { if (strncmp(s, ex_tok->op, ex_tok->size) == 0) return *ex_tok; ++ex_tok; } return not_found; } bool fillLexerFromString(const char* s, t_lexer* lexer) { t_oplist current; const char* prev = s; /* Previous time we encountered a known token. */ while (s && *s) { /* Handle \\ escaping */ if (*s == '\\') { ++s; continue; } /* Search any know token */ current = searchTokenType(s); /* if current.type == TOKEN_OP_* add +1 a counter ! if current.type == TOKEN_CL_* dec -1 a counter ! At the end, check if the counter is equal to 0. If not, there is a syntax error! */ /* Find another token ? let's see if we have something inbetween */ if ((current.op != 0 || *s == '"' || *s == '\'') && prev != s) addToLexer(lexer, prev, s - prev, TOKEN_NAME); /* Token found */ if (current.op != 0) { s += current.size; if (current.type != TOKEN_EAT) addToLexer(lexer, current.op, current.size, current.type); prev = s; } /* Token not found, but could be an escaped string */ else if (*s == '"' || *s == '\'') { /* handleEscaping(); Handle it for real */ ++s; while (*s && *s != '\'' && *s != '"') /* <- dumb function */ ++s; if (!*s || (*s != '\'' && *s != '"')) { /* string not finished! */ return 0; } ++s; } else ++s; } /* Handle what's remain at the end of the input */ if (prev != s) addToLexer(lexer, prev, s - prev, TOKEN_NAME); return 1; } void print(const t_lexer* lexer) { uint32_t i = 0; for (i = 0; i < lexer->size; ++i) printf("<%s (%i)> ", lexer->tokens[i].content, lexer->tokens[i].type); printf("\n"); } int main() { const char* cmd = "for i in seq 1 10 20; do echo toto &&echo titi\n||read \"hello && escape\"; done"; t_lexer lexer; lexer.size = 0; if (!fillLexerFromString(cmd, &lexer)) printf("Syntax error !\n"); print(&lexer); return 0; }
Améliorez votre expérience CodeS-SourceS avec ce plugin:
http://codes-sources.commentcamarche.net/forum/affich-10000111-plugin-better-cs-2#cptpingu-signature
#ifndef sh42_H
# define sh42_H
# include "libft.h" // Contient des fonctions de la libc
# include <termios.h>
int sh_SetTermSettings(struct termios *attributes);
int sh_ResetTermSettings(struct termios *attributes);
void sh_ExecShell42(int ac, char **av, char **ep);
#endif
#include "sh42.h"
int sh_SetTermSettings(struct termios *attributes)
{
if (tcgetattr(0, attributes) == -1)
return (-1);
attributes->c_lflag &= ~ICANON;
attributes->c_lflag &= ~ECHO;
attributes->c_cc[VMIN] = 1; //On récupère la main dès que au moins 1 caractère est lu par read
attributes->c_cc[VTIME] = 0;
if (tcsetattr(0, TCSADRAIN, attributes) == -1)
return (-1);
return (0);
}
int sh_ResetTermSettings(struct termios *attributes)
{
if (tcgetattr(0, attributes) == -1)
return (-1);
attributes->c_lflag |= ICANON;
attributes->c_lflag |= ECHO;
if (tcsetattr(0, TCSADRAIN, attributes) == -1)
return (-1);
return (0);
}
int main(int ac, char **av, char **ep)
{
struct termios attributes;
if (sh_SetTermSettings(&attributes) == -1)
return (-1);
// sh_ExecShell42(ac, av, ep); //A coder! ^^
if (sh_ResetTermSettings(&attributes) == -1)
return (-1);
return (0);
}
Améliorez votre expérience CodeS-SourceS avec ce plugin:
http://codes-sources.commentcamarche.net/forum/affich-10000111-plugin-better-cs-2#cptpingu-signature
Vous n’avez pas trouvé la réponse que vous recherchez ?
Posez votre questionUne genre d'strsplit, je zappe les blancs et les tabulations et je renvoi un tableau de char* . Je pensai commencer par ça en effet!
ls -a && echo "je fais un \"ls\" -a (youpi)" || (echo "fail" | cat -A) & # un commentaire
ls
-a
&&
echo
"je fais un \"ls\" -a (youpi)"
||
(
echo
"fail"
|
cat
-A
)
&
"une erreur conne
'une autre erreur hihi
une erreur conne"
une autre erreur hihi'
toto \
Alors là.. ^^ Je vais me pencher sur les arbres syntaxiques. J'avoue que j'essayais de m'en passer. Mais ce sera certainement bien plus propre que ma chaîne de token et son interprétation.. Je bouquine et je reviens.
Pour la lecture à partir d'un fichier, on est d'accord c'est genre pour mettre tout un tas de commandes et pouvoir tester mes retour VS ceux d'un shell fonctionnel??
Améliorez votre expérience CodeS-SourceS avec ce plugin:
http://codes-sources.commentcamarche.net/forum/affich-10000111-plugin-better-cs-2#cptpingu-signature
LEXER.H
#ifndef LEXER_H
# define LEXER_H
# define INDEX ((i == 0) ? i : (i - 1))
# define RULES 6
# define ESCAPMENT "\\"
# define STANDARD " \t\n"
# define FRAME "\"\'"
# define SEPARATOR ";&"
# define REDIRECTOR "<>|"
# include "libft.h"
typedef enum e_vstate
{
InSynError = -2,
InLexError = -1,
Standard,
InEscapment,
InFrame,
InIdentifier,
InSeparator,
InRedirector
} t_vstate;
typedef enum e_type
{
None,
Escapment,
Frame,
Identifier,
Separator,
Redirector
} t_type;
typedef struct s_state
{
t_vstate old;
t_vstate curr;
} t_state;
typedef struct s_token
{
t_type type;
char *value;
} t_token;
typedef struct s_lexer
{
t_list *tokenlst;
int err;
int err_index;
t_type err_type;
} t_lexer;
typedef t_vstate (*t_func)(char *, int);
t_lexer *str_lex(char *str);
int maj_tokenlst(t_list **atokenlst, t_state state, char *str, int i);
void init_rules_tab(t_func *rules_tab);
void destroy_tokenlst(t_list **atokenlst);
void destroy_lexed(t_lexer **lexed);
t_vstate rules_standard(char *str, int i);
t_vstate rules_frame(char *str, int i);
t_vstate rules_escapment(char *str, int i);
t_vstate rules_identifier(char *str, int i);
t_vstate rules_separator(char *str, int i);
t_vstate rules_redirector(char *str, int i);
#endif
LEXER.C
#include "lexer.h"
static t_lexer *get_return(t_list *tokenlst, t_state state, int i)
{
t_lexer *lexed;
if (tokenlst == NULL)
return (NULL);
lexed = (t_lexer *)malloc(sizeof(t_lexer));
if (lexed == NULL)
{
destroy_tokenlst(&tokenlst);
return (NULL);
}
lexed->tokenlst = tokenlst;
if (state.curr >= Standard)
{
lexed->err = None;
lexed->err_index = -1;
lexed->err_type = None;
}
else
{
lexed->err = state.curr;
lexed->err_index = i;
lexed->err_type = (t_type)state.old;
}
return (lexed);
}
static t_list *get_token(t_type type, char *str, int i, int len)
{
t_list *token;
t_token data;
data.type = type;
data.value = ft_strsub(str, i, len);
if (data.value == NULL)
return (NULL);
else
{
token = ft_lstnew((void *)&data, sizeof(t_token));
if (token == NULL)
free(data.value);
}
return (token);
}
int maj_tokenlst(t_list **atokenlst, t_state state, char *str, int i)
{
static int len = 1;
t_list *token;
if (state.old == state.curr && str[i] != '\0')
len++;
else
{
token = get_token((t_type)state.old, str, (i - len), len);
if (token == NULL)
{
destroy_tokenlst(atokenlst);
return (0);
}
ft_lstadd(atokenlst, token);
len = 1;
}
return (1);
}
t_lexer *str_lex(char *str)
{
t_func rules_tab[RULES];
t_list *tokenlst;
t_state state;
int i;
int ret;
init_rules_tab(rules_tab);
tokenlst = NULL;
state.old = Standard;
i = 0;
ret = 1;
while (str[INDEX] != '\0')
{
state.curr = rules_tab[state.old](str, i);
if (state.old != Standard)
ret = maj_tokenlst(&tokenlst, state, str, i);
if (ret == 0 || state.curr < Standard)
return (get_return(tokenlst, state, i));
state.old = state.curr;
i++;
}
return (get_return(tokenlst, state, i));
}
EXTERN.C
#include "lexer.h"
void init_rules_tab(t_func *rules_tab)
{
rules_tab[Standard] = rules_standard;
rules_tab[InFrame] = rules_frame;
rules_tab[InEscapment] = rules_escapment;
rules_tab[InIdentifier] = rules_identifier;
rules_tab[InSeparator] = rules_separator;
rules_tab[InRedirector] = rules_redirector;
}
void destroy_tokenlst(t_list **atokenlst)
{
t_list *tmp;
while (*atokenlst != NULL)
{
tmp = (*atokenlst)->next;
free(((t_token *)(*atokenlst)->content)->value);
((t_token *)(*atokenlst)->content)->value = NULL;
free((*atokenlst)->content);
(*atokenlst)->content = NULL;
free(*atokenlst);
(*atokenlst) = tmp;
}
}
void destroy_lexed(t_lexer **alexed)
{
destroy_tokenlst(&((*alexed)->tokenlst));
free(*alexed);
(*alexed) = NULL;
}
RULES.C
#include "lexer.h"
t_vstate rules_standard(char *str, int i)
{
if (ft_strchr(STANDARD, str[i]))
return (Standard);
else if (ft_strchr(ESCAPMENT, str[i]))
return (InEscapment);
else if (ft_strchr(SEPARATOR, str[i]))
return (InSeparator);
else if (ft_strchr(REDIRECTOR, str[i]))
return (InRedirector);
else if (ft_strchr(FRAME, str[i]))
return (InFrame);
else if (ft_isprint(str[i]) != 0)
return (InIdentifier);
return (InLexError);
}
t_vstate rules_escapment(char *str, int i)
{
static int len = 1;
if (len == 1)
{
len++;
return (InEscapment);
}
else if (ft_strchr(STANDARD, str[i]))
return (len = 1, Standard);
else if (ft_strchr(ESCAPMENT, str[i]))
return (len = 1, InEscapment);
else if (ft_strchr(SEPARATOR, str[i]))
return (len = 1, InSeparator);
else if (ft_strchr(REDIRECTOR, str[i]))
return (len = 1, InRedirector);
else if (ft_strchr(FRAME, str[i]))
return (len = 1, InFrame);
else if (ft_isprint(str[i]) != 0)
return (len = 1, InIdentifier);
return (InLexError);
}
t_vstate rules_identifier(char *str, int i)
{
if (ft_strchr(STANDARD, str[i]))
return (Standard);
else if (ft_strchr(ESCAPMENT, str[i]))
return (InEscapment);
else if (ft_strchr(SEPARATOR, str[i]))
return (InSeparator);
else if (ft_strchr(REDIRECTOR, str[i]))
return (InRedirector);
else if (ft_strchr(FRAME, str[i]))
return (InFrame);
else if (ft_isprint(str[i]) != 0)
return (InIdentifier);
return (InLexError);
}
t_vstate rules_frame(char *str, int i)
{
static int len = 1;
static char c;
if (len == 1)
{
c = str[i - 1];
return (++len, (str[i] == '\0') ? InLexError : InFrame);
}
else if (str[i] == '\0' && c != '\0')
return (InLexError);
else if ((str[i] != c && c != '\0') || (str[i] == c && str[i - 1] == '\\'))
return (InFrame);
else if (str[i] == c)
return (c = '\0', InFrame);
else if (ft_strchr(STANDARD, str[i]))
return (len = 1, Standard);
else if (ft_strchr(ESCAPMENT, str[i]))
return (len = 1, InEscapment);
else if (ft_strchr(SEPARATOR, str[i]))
return (len = 1, InSeparator);
else if (ft_strchr(REDIRECTOR, str[i]))
return (len = 1, InRedirector);
else if (ft_isprint(str[i]) != 0)
return (len = 1, InIdentifier);
return (InLexError);
}
t_vstate rules_separator(char *str, int i)
{
static int len = 1;
if (ft_strchr(SEPARATOR, str[i]) && str[i] != '\0')
{
len++;
if ((len == 2 && (str[i] != str[i - 1] || str[i] == ';')) || len > 2)
return (InLexError);
return (InSeparator);
}
else if (ft_strchr(STANDARD, str[i]))
return (len = 1, Standard);
else if (ft_strchr(ESCAPMENT, str[i]))
return (len = 1, InEscapment);
else if (ft_strchr(REDIRECTOR, str[i]))
return (InSynError);
else if (ft_strchr(FRAME, str[i]))
return (len = 1, InFrame);
else if (ft_isprint(str[i]) != 0)
return (len = 1, InIdentifier);
return (InLexError);
}
t_vstate rules_redirector(char *str, int i)
{
static int len = 1;
if (ft_strchr(REDIRECTOR, str[i]) && str[i] != '\0')
{
len++;
if ((len == 2 && (str[i] != str[i - 1] || str[i] == '|')) || len > 2)
return (InLexError);
return (InRedirector);
}
else if (ft_strchr(STANDARD, str[i]))
return (len = 1, Standard);
else if (ft_strchr(ESCAPMENT, str[i]))
return (len = 1, InEscapment);
else if (ft_strchr(SEPARATOR, str[i]))
return (InSynError);
else if (ft_strchr(FRAME, str[i]))
return (len = 1, InFrame);
else if (ft_isprint(str[i]) != 0)
return (len = 1, InIdentifier);
return (InLexError);
}
MAIN.C
#include "lexer.h"
static void print_lexed(t_lexer *lexed)
{
t_list *drive;
if (lexed == NULL)
ft_putstr("Malloc error or empty str\n\n");
else
{
ft_putstr("lexed error\t\t");
if (lexed->err == 0)
ft_putendl("None");
else if (lexed->err == InLexError)
ft_putendl("Lexical Error");
else if (lexed->err == InSynError)
ft_putendl("Syntax Error");
ft_putstr("lexed error_type\t");
if (lexed->err_type == None)
ft_putendl("None");
else if (lexed->err_type == Escapment)
ft_putendl("Escapment");
else if (lexed->err_type == Frame)
ft_putendl("Frame");
else if (lexed->err_type == Identifier)
ft_putendl("Identifier");
else if (lexed->err_type == Separator)
ft_putendl("Separator");
else if (lexed->err_type == Redirector)
ft_putendl("Redirector");
ft_putstr("lexed error_index\t");
ft_putnbr(lexed->err_index);
ft_putstr("\n\n");
drive = lexed->tokenlst;
while (drive != NULL)
{
if (((t_token *)(drive->content))->type == None)
ft_putstr("None");
else if (((t_token *)(drive->content))->type == Escapment)
ft_putstr("Escapment");
else if (((t_token *)(drive->content))->type == Frame)
ft_putstr("Frame\t");
else if (((t_token *)(drive->content))->type == Identifier)
ft_putstr("Identifier");
else if (((t_token *)(drive->content))->type == Separator)
ft_putstr("Separator");
else if (((t_token *)(drive->content))->type == Redirector)
ft_putstr("Redirector");
ft_putstr("\t\t[");
ft_putstr(((t_token *)(drive->content))->value);
ft_putendl("]");
drive = drive->next;
}
ft_putchar('\n');
}
ft_putendl("---------------------------------------------------------\n");
}
int main(int ac, char **av)
{
t_lexer *lexed;
int i;
if (ac < 2)
write(1, "To few argument\n", 16);
else
{
i = 1;
while (i < ac)
{
lexed = str_lex(av[i++]);
print_lexed(lexed);
if (lexed)
destroy_lexed(&lexed);
}
}
return (0);
}