From a49bbbdcc897630432be9e390e88c4a7cfa5e341 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Luttringer?= Date: Wed, 23 Aug 2006 16:46:41 +0000 Subject: [PATCH] reorganisation des options ajout des fonctions pour les alias debut de reecriture du lexer final --- src/Makefile.am | 12 +- src/alias/alias.c | 73 ++++ src/alias/alias.h | 55 +++ src/common/common.h | 11 +- src/common/isdigitstr.c | 19 + src/opt/opt.h | 29 -- src/opt/opt_init.c | 26 -- src/{opt/opt.c => option/option.c} | 62 ++-- src/option/option.h | 89 +++++ .../opt_parser.c => option/option_parser.c} | 14 +- src/parser/lexer.c | 337 +++++++++++------- src/parser/parser.c | 197 +++++++--- src/parser/parser.h | 91 +++-- src/shell/shell.h | 10 +- src/shell/shell_entry.c | 8 +- src/shell/shell_init.c | 7 +- 16 files changed, 717 insertions(+), 323 deletions(-) create mode 100644 src/alias/alias.c create mode 100644 src/alias/alias.h create mode 100644 src/common/isdigitstr.c delete mode 100644 src/opt/opt.h delete mode 100644 src/opt/opt_init.c rename src/{opt/opt.c => option/option.c} (50%) create mode 100644 src/option/option.h rename src/{opt/opt_parser.c => option/option_parser.c} (76%) diff --git a/src/Makefile.am b/src/Makefile.am index 6c66f2a..39089ad 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -4,7 +4,9 @@ bin_PROGRAMS=42sh #42sh_LDADD = parser/libparse.a ../check/leaktrack/libmem.a evalexpr/libevalexpr.a -42sh_SOURCES= ast/ast.h \ +42sh_SOURCES= alias/alias.h \ + alias/alias.c \ + ast/ast.h \ ast/ast_and.c \ ast/ast_bang.c \ ast/ast_case.c \ @@ -21,6 +23,7 @@ bin_PROGRAMS=42sh ast/ast_until.c \ ast/ast_while.c \ common/common.h \ + common/isdigitstr.c \ common/mem.h \ common/strmerge.c \ common/strvmerge.c \ @@ -28,10 +31,9 @@ bin_PROGRAMS=42sh common/basename.c \ exec/exec.h \ exec/exec_ast.c \ - opt/opt.h \ - opt/opt.c \ - opt/opt_init.c \ - opt/opt_parser.c \ + option/option.h \ + option/option.c \ + option/option_parser.c \ parser/parser.h \ parser/parser.c \ parser/lexer.c \ diff --git a/src/alias/alias.c b/src/alias/alias.c new file mode 100644 index 0000000..2216285 --- /dev/null +++ b/src/alias/alias.c @@ -0,0 +1,73 @@ +/* +** alias.c for 42sh +** +** Made by Seblu +** Login +** +** Started on Wed Aug 23 00:39:17 2006 Seblu +** Last update Wed Aug 23 18:47:59 2006 Seblu +*/ + +#include +#include "alias.h" +#include "../common/mem.h" + +static size_t step = 5; + +ts_aliases *alias_init(void) +{ + ts_aliases *new; + + secmalloc(new, sizeof (ts_aliases)); + new->size = step; + new->pos = 0; + new->db = NULL; + return new; +} + +void alias_add(ts_aliases *aliases, const char *name, const char *value) +{ + ts_alias *new; + int freeplace = 0; + size_t index; + + //check if already exist and if free place exist + for (register int i = 0; aliases && aliases->db[i]; ++i) + if (!strcmp(aliases->db[i]->name, name)) { + free(aliases->db[i]->value); + aliases->db[i]->value = strdup(value); + return; + } + else if (!freeplace && *aliases->db[i]->name == 0) + index = i; + //if a place is free, fill it + if (freeplace) { + aliases->db[index]->name = strdup(name); + aliases->db[index]->value = strdup(value); + return; + } + //create a new one + secmalloc(new, sizeof (ts_alias)); + new->name = strdup(name); + new->value = strdup(value); + //add a new alias if not find + if (aliases->pos >= aliases->size) { + aliases->size += step; + secrealloc(aliases->db, aliases->db, aliases->size * sizeof (ts_alias)); + } + aliases->db[aliases->pos] = new; + ++aliases->pos; +} + +int alias_remove(ts_aliases *aliases, const char *name) +{ + //find alias index + for (register int i = 0; aliases && aliases->db[i]; ++i) + if (!strcmp(aliases->db[i]->name, name)) { + free(aliases->db[i]->name); + free(aliases->db[i]->value); + aliases->db[i]->name = ""; + return 1; + } + return 0; +} diff --git a/src/alias/alias.h b/src/alias/alias.h new file mode 100644 index 0000000..775328c --- /dev/null +++ b/src/alias/alias.h @@ -0,0 +1,55 @@ +/* +** alias.h for 42sh +** +** Made by Seblu +** Login +** +** Started on Wed Aug 23 00:32:09 2006 Seblu +** Last update Wed Aug 23 18:44:52 2006 Seblu +*/ + +#ifndef ALIAS_H_ +# define ALIAS_H_ + +# include + +typedef struct s_alias +{ + char *name; + char *value; +} ts_alias; + +typedef struct s_aliases +{ + size_t size; + size_t pos; + ts_alias **db; +} ts_aliases; + +/*! +** Create a new aliases database +** +** @return new alias database +*/ +ts_aliases *alias_init(void); + +/*! +** Add an alias into an alias database +** +** @param aliases alias database +** @param name new alias name +** @param value new alias value +*/ +void alias_add(ts_aliases *aliases, const char *name, const char *value); + +/*! +** Remove an alias into an alias database +** +** @param aliases alias database +** @param name alias name to remove +** +** @return true, if alias was found in database, else false +*/ +int alias_remove(ts_aliases *aliases, const char *name); + +#endif diff --git a/src/common/common.h b/src/common/common.h index 4801ef9..f6c92ed 100644 --- a/src/common/common.h +++ b/src/common/common.h @@ -5,7 +5,7 @@ ** Login ** ** Started on Sun Jul 30 03:59:48 2006 Seblu -** Last update Thu Aug 3 06:01:23 2006 Seblu +** Last update Tue Aug 22 22:41:29 2006 Seblu */ #ifndef COMMON_H_ @@ -52,4 +52,13 @@ char *basename(const char *path); */ char *strndup(const char *str, size_t n); +/*! +** Compute if string is composed only by digit +** +** @param str string to test +** +** @return boolean result +*/ +int isdigitstr(const char *str); + #endif diff --git a/src/common/isdigitstr.c b/src/common/isdigitstr.c new file mode 100644 index 0000000..eaf29ac --- /dev/null +++ b/src/common/isdigitstr.c @@ -0,0 +1,19 @@ +/* +** isdigitstr.c for 42sh +** +** Made by Seblu +** Login +** +** Started on Sun Nov 13 08:13:54 2005 Seblu +** Last update Tue Aug 22 22:43:54 2006 Seblu +*/ + +int isdigitstr(const char *str) +{ + if (*str == 0) + return 0; + for (; *str; str++) + if (!(*str >= '0' && *str <= '9')) + return 0; + return 1; +} diff --git a/src/opt/opt.h b/src/opt/opt.h deleted file mode 100644 index 5a6a888..0000000 --- a/src/opt/opt.h +++ /dev/null @@ -1,29 +0,0 @@ -/* -** opt.h for 42sh -** -** Made by Seblu -** Login -** -** Started on Tue Mar 21 18:50:03 2006 Seblu -** Last update Sun Jul 30 03:51:48 2006 Seblu -*/ - -#ifndef OPT_H_ -# define OPT_H_ - -#define NBR_OPT 8 - -typedef struct -{ - signed char item[NBR_OPT]; - char *command; -} ts_opt; - -ts_opt *opt_init(void); -void opt_parser(int argc, char *argv[], ts_opt *opt); -int opt_set(const char *name, ts_opt *shopt); -int opt_unset(const char *name, ts_opt *shopt); -int opt_isset(const char *name, const ts_opt *shopt); -const char **opt_get(void); - -#endif /* ! OPT_H_ */ diff --git a/src/opt/opt_init.c b/src/opt/opt_init.c deleted file mode 100644 index 02bf776..0000000 --- a/src/opt/opt_init.c +++ /dev/null @@ -1,26 +0,0 @@ -/* -** opt_init.c for 42sh -** -** Made by Seblu -** Login -** -** Started on Sun Jul 30 03:33:09 2006 Seblu -** Last update Thu Aug 3 02:45:51 2006 Seblu -*/ - -#include "opt.h" -#include "../common/mem.h" - -/*! -** Create a new option structure -** -** @return A new option structure -*/ -ts_opt *opt_init(void) -{ - ts_opt *new; - - secmalloc(new, sizeof (ts_opt)); - new->command = NULL; - return new; -} diff --git a/src/opt/opt.c b/src/option/option.c similarity index 50% rename from src/opt/opt.c rename to src/option/option.c index 641a751..a11956f 100644 --- a/src/opt/opt.c +++ b/src/option/option.c @@ -5,14 +5,21 @@ ** Login ** ** Started on Tue Mar 21 19:00:38 2006 Seblu -** Last update Sun Jul 30 03:41:36 2006 Seblu +** Last update Wed Aug 23 18:37:38 2006 Seblu +*/ + +/* +** ============ +** DECLARATIONS +** ============ */ #include +#include "option.h" #include "../shell/shell.h" -#include "opt.h" +#include "../common/mem.h" -static const char *opts_table[NBR_OPT] = +static const char *opts_table[NBR_OPTION] = { "xpg_echo", "dotglob", @@ -22,15 +29,22 @@ static const char *opts_table[NBR_OPT] = "expand_aliases", }; -/*! -** Set a shell option -** -** @param name name of the option to set -** @param shopt structure to apply -** -** @return 0 on failure, else 1 +/* +** =========== +** DEFINITIONS +** =========== */ -int opt_set(const char *name, ts_opt *shopt) + +ts_options *option_init(void) +{ + ts_options *new; + + secmalloc(new, sizeof (ts_options)); + new->command = NULL; + return new; +} + +int option_set(ts_options *shopt, const char *name) { register int i; @@ -43,15 +57,7 @@ int opt_set(const char *name, ts_opt *shopt) return 0; } -/*! -** Unset a shell option -** -** @param name name of the option to unset -** @param shopt structure to apply -** -** @return 0 on failure, else 1 -*/ -int opt_unset(const char *name, ts_opt *shopt) +int option_unset(ts_options *shopt, const char *name) { register int i; @@ -64,16 +70,7 @@ int opt_unset(const char *name, ts_opt *shopt) return 0; } - -/*! -** Tell if an option is set. if option nane is not set return -1 -** -** @param name name to find -** @param shopt structure where find -** -** @return 0 if unset, 1 if set and -1 if not exist -*/ -int opt_isset(const char *name, const ts_opt *shopt) +int option_isset(const ts_options *shopt, const char *name) { register int i; @@ -83,11 +80,6 @@ int opt_isset(const char *name, const ts_opt *shopt) return -1; } -/*! -** Return a list of know opt -** -** @return list of opt -*/ const char **opt_get() { return opts_table; diff --git a/src/option/option.h b/src/option/option.h new file mode 100644 index 0000000..3ee0af4 --- /dev/null +++ b/src/option/option.h @@ -0,0 +1,89 @@ +/* +** option.h for 42sh +** +** Made by Seblu +** Login +** +** Started on Tue Mar 21 18:50:03 2006 Seblu +** Last update Wed Aug 23 18:39:43 2006 Seblu +*/ + +#ifndef OPTION_H_ +# define OPTION_H_ + +#define NBR_OPTION 8 + +#define DEBUG_OPTION 0 + +typedef struct s_options +{ + signed char item[NBR_OPTION]; + char *command; +} ts_options; + +/* +** ============== +** FILE: option.c +** ============== +*/ + +/*! +** Create a new options structure +** +** @return A new options structure +*/ +ts_options *option_init(void); + +/*! +** Set a shell option +** +** @param shopt structure to apply +** @param name name of the option to set +** +** @return 0 on failure, else 1 +*/ +int option_set(ts_options *shopt, const char *name); + +/*! +** Unset a shell option +** +** @param shopt structure to apply +** @param name name of the option to unset +** +** @return 0 on failure, else 1 +*/ +int option_unset(ts_options *shopt, const char *name); + +/*! +** Tell if an option is set. if option nane is not set return -1 +** +** @param shopt structure where find +** @param name name to find +** +** @return 0 if unset, 1 if set and -1 if not exist +*/ +int option_isset(const ts_options *shopt, const char *name); + +/*! +** Return a list of know opt +** +** @return list of opt +*/ +const char **opt_get(); + +/* +** ===================== +** FILE: option_parser.c +** ===================== +*/ + +/*! +** Parse the command line +** +** @param opt shell opt structure to set with options +** @param argc program argc +** @param argv program argv +*/ +void option_parser(ts_options *opt, int argc, char **argv); + +#endif diff --git a/src/opt/opt_parser.c b/src/option/option_parser.c similarity index 76% rename from src/opt/opt_parser.c rename to src/option/option_parser.c index f590b14..7376e5f 100644 --- a/src/opt/opt_parser.c +++ b/src/option/option_parser.c @@ -1,15 +1,15 @@ /* -** opt_parser.c for 42sh +** option_parser.c for 42sh ** ** Made by Seblu ** Login ** ** Started on Sun Jul 30 03:28:26 2006 Seblu -** Last update Thu Aug 3 05:22:32 2006 Seblu +** Last update Wed Aug 23 18:39:19 2006 Seblu */ #include -#include "opt.h" +#include "option.h" #include "../common/common.h" /*! @@ -19,16 +19,16 @@ ** @param argv program argv ** @param opt shell opt structure to set with options */ -void opt_parser(int argc, char **argv, ts_opt *opt) +void option_parser(ts_options *opt, int argc, char **argv) { -#ifdef DEBUG42 +#if DEBUG_OPTION == 1 printf("* Option Parser\n"); #endif if (argc == 1) return; for (int i = 1; i < argc; ++i) { -#ifdef DEBUG42 +#if DEBUG_OPTION == 1 printf("argv[%d]=%s\n", i, argv[i]); #endif const char *copt = argv[i]; @@ -37,7 +37,7 @@ void opt_parser(int argc, char **argv, ts_opt *opt) if (copt[1] == 'c') { opt->command = strvmerge((const char**)argv + i + 1); -#ifdef DEBUG42 +#if DEBUG_OPTION == 1 printf("option c: %s\n", opt->command); #endif break; diff --git a/src/parser/lexer.c b/src/parser/lexer.c index 4cf6542..8d0995b 100644 --- a/src/parser/lexer.c +++ b/src/parser/lexer.c @@ -5,7 +5,7 @@ ** Login ** ** Started on Sun Jul 30 04:36:53 2006 Seblu -** Last update Sat Aug 19 01:41:32 2006 Seblu +** Last update Wed Aug 23 18:05:56 2006 Seblu */ #include @@ -15,23 +15,30 @@ #include "../shell/shell.h" #include "../readline/readline.h" #include "../common/common.h" +#include "../common/mem.h" -#define is_quote(c) ((c) == '"' || (c) == '\'' || (c) == '`') -#define is_sep(c) ((c) == ' ' || (c) == '\t' || (c) == '\v') - -static int lexer_reconize(ts_parser *parser); - -static void lexer_eat(ts_parser *lex); - -static ts_token token_create(te_tokenid id, const char *string); +/* +** Token recognition rationale: +** - Separator are chars which used to cut token but which are deleted. +** - Operators are chars which used to cut token and which are returned as token. +** - Keywords are chars which are collapsed by tokens and are reserved. +** - Others are chars considered like words. +*/ -static void token_set(ts_token *token, te_tokenid id, const char *s); +/* +** ============ +** DECLARATIONS +** ============ +*/ -ts_token operators[] = +static ts_token operators[] = { + {TOK_NEWLINE, "\n"}, {TOK_AND, "&&"}, {TOK_OR, "||"}, {TOK_DSEMI, ";;"}, + {TOK_LESS, "<"}, + {TOK_GREAT, ">"}, {TOK_DLESS, "<<"}, {TOK_DGREAT, ">>"}, {TOK_LESSAND, "<&"}, @@ -41,158 +48,240 @@ ts_token operators[] = {TOK_CLOBBER, ">|"}, {TOK_SEP, ";"}, {TOK_SEPAND, "&"}, - {TOK_NEWLINE, "\n"}, - {0, NULL} + {TOK_NONE, NULL} }; -ts_token keywords[] = - { - {TOK_IF, "if"}, - {TOK_THEN, "then"}, - {TOK_ELSE, "else"}, - {TOK_FI, "fi"}, - {TOK_ELIF, "elif"}, - {TOK_DO, "do"}, - {TOK_DONE, "done"}, - {TOK_CASE, "case"}, - {TOK_ESAC, "esac"}, - {TOK_WHILE, "while"}, - {TOK_UNTIL, "until"}, - {TOK_FOR, "for"}, - {TOK_IN, "in"}, - {TOK_LBRACE, "{"}, - {TOK_RBRACE, "}"}, - {TOK_BANG, "!"}, - {0, NULL} - }; +/* static ts_token keywords[] = */ +/* { */ +/* {TOK_IF, "if"}, */ +/* {TOK_THEN, "then"}, */ +/* {TOK_ELSE, "else"}, */ +/* {TOK_FI, "fi"}, */ +/* {TOK_ELIF, "elif"}, */ +/* {TOK_DO, "do"}, */ +/* {TOK_DONE, "done"}, */ +/* {TOK_CASE, "case"}, */ +/* {TOK_ESAC, "esac"}, */ +/* {TOK_WHILE, "while"}, */ +/* {TOK_UNTIL, "until"}, */ +/* {TOK_FOR, "for"}, */ +/* {TOK_IN, "in"}, */ +/* {TOK_LBRACE, "{"}, */ +/* {TOK_RBRACE, "}"}, */ +/* {TOK_BANG, "!"}, */ +/* {TOK_NONE, NULL} */ +/* }; */ + +/*! +** Return a predicat about c is a quote +** +** @param c Must be a character +** +** @return true if c is a quote +*/ +#define is_quote(c) ((c) == '"' || (c) == '\'' || (c) == '`') + +/*! +** Return a predicat about c is a separator +** +** @param c Must be a character +** +** @return true if c is a separator +*/ +#define is_sep(c) ((c) == ' ' || (c) == '\t' || (c) == '\v') + +/*! +** Call readline while it's necessary to reconize a token. +** +** @param lex lexer struct +*/ +static void lexer_eat(ts_lexer *lex); + +/*! +** Cut and reconize a token. +** +** @param lexer lexer struct +** +** @return 1, if someting is reconized, else 0 +*/ +static int lexer_reconize(ts_lexer *lexer); -void lexer_reset(ts_parser *parser) +/*! +** Correctly set a token. In first, it call macro token_free to +** desallow memory if it's a word. +** +** @param token token to set +** @param id new token id +** @param s new token string +*/ +static void token_set(ts_token *token, te_tokenid id, const char *s); + + +/* +** =========== +** DEFINITIONS +** =========== +*/ + +ts_lexer *lexer_init(FILE *fs) { - token_set(&parser->token, TOK_NONE, NULL); - if (parser->buf) free(parser->buf); - parser->buf = NULL; - parser->buf_size = parser->buf_pos = 0; + ts_lexer *new; + + secmalloc(new, sizeof (ts_lexer)); + fflush(fs); + new->fs = fs; + new->buf = NULL; + new->buf_size = new->buf_pos = 0; + new->status = LEXER_READY; + return new; } -ts_token lexer_lookahead(ts_parser *parser) +int lexer_start(ts_lexer *lexer) { - if (parser->status != PARSE_OK) - return token_create(TOK_ERR, NULL); - if (parser->token.id == TOK_NONE) - lexer_eat(parser); - return parser->token; + if (lexer->status == LEXER_END) + return 0; + token_set(&lexer->token, TOK_NONE, NULL); + if (lexer->buf) free(lexer->buf); + lexer->buf = NULL; + lexer->buf_size = lexer->buf_pos = 0; + return 1; } -ts_token lexer_gettoken(ts_parser *parser) +ts_token lexer_lookahead(ts_lexer *lexer) { - ts_token buf; - - if (parser->status != PARSE_OK) - return token_create(TOK_ERR, NULL); - if (parser->token.id == TOK_NONE) - lexer_eat(parser); - buf = parser->token; - parser->token = token_create(TOK_NONE, NULL); - return buf; + if (lexer->token.id == TOK_NONE) + lexer_eat(lexer); + return lexer->token; } -static ts_token token_create(te_tokenid id, const char *string) +ts_token lexer_gettoken(ts_lexer *lexer) { - ts_token new = { id, string }; + ts_token buf; - return new; + if (lexer->token.id == TOK_EOF) + return lexer->token; + if (lexer->token.id == TOK_NONE) + lexer_eat(lexer); + buf = lexer->token; + lexer->token.id = TOK_NONE; + lexer->token.str = NULL; + return buf; } static void token_set(ts_token *token, te_tokenid id, const char *s) { - if (token->id == TOK_WORD && token->str) - free((char*) token->str); + token_free(*token); token->id = id; token->str = s; } -void lexer_eat(ts_parser *parser) +static void lexer_eat(ts_lexer *lexer) { char *lbuf, *lbuf2; - // return EOF (the last), if file is ended - if (parser->status == PARSE_END) - return; - //if line is void, start readding - if (parser->buf_size == 0) { - if ((parser->buf = readline(get_prompt(TYPE_PS1))) == NULL) { - token_set(&parser->token, TOK_EOF, "eof"); - parser->status = PARSE_END; + //if line is void, start readding with good prompt + if (lexer->buf_size == 0) { + if ((lexer->buf = readline(get_prompt(TYPE_PS1))) == NULL) { + token_set(&lexer->token, TOK_EOF, "EOF"); + lexer->status = LEXER_END; return; } - parser->buf_pos = 0; - parser->buf_size = strlen(parser->buf); + lexer->buf_pos = 0; + lexer->buf_size = strlen(lexer->buf); } //read line while a token will not be reconized - while (!lexer_reconize(parser)) { - if ((lbuf2 = readline(get_prompt(TYPE_PS2))) == NULL) { - token_set(&parser->token, TOK_EOF, "eof"); - parser->status = PARSE_END; - return; + while (!lexer_reconize(lexer)) { + //change last \n by ; + if (lexer->buf[lexer->buf_size - 1] == '\n') + lexer->buf[lexer->buf_size - 1] = ';'; + if ((lbuf2 = readline(get_prompt(TYPE_PS2))) == NULL) + lexer->status = LEXER_END; + else { + lbuf = lexer->buf; + lexer->buf = strmerge(2, lbuf, lbuf2); + lexer->buf_size = strlen(lexer->buf); + free(lbuf), free(lbuf2); } - lbuf = parser->buf; - parser->buf = strmerge(2, lbuf, lbuf2); - parser->buf_size = strlen(parser->buf); - free(lbuf), free(lbuf2); } } -static int lexer_reconize(ts_parser *parser) +/* static int lexer_cutter(ts_lexer *lexer) */ +/* { */ +/* const char *buf = lexer->buf; */ +/* const size_t buf_size = lexer->buf_size; */ +/* // size_t *buf_pos = &lexer->buf_pos; */ +/* size_t token_start, token_pos; */ +/* int end_found = 0; */ +/* char backed = 0, quoted = 0, commented = 0; */ + +/* token_start = token_pos = lexer->buf_pos; */ + +/* } */ + +static int lexer_reconize(ts_lexer *lexer) { - const char *buf = parser->buf; - const size_t buf_size = parser->buf_size; - size_t *buf_pos = &parser->buf_pos; - size_t token_start; - size_t token_pos; + const char *buf = lexer->buf; + const size_t buf_size = lexer->buf_size; + size_t *buf_pos = &lexer->buf_pos; + size_t token_start, token_pos; int end_found = 0; - char backed = 0; - char quoted = 0; - - //eat spaces (" ",\t, \v) - while (*buf_pos < buf_size && - is_sep(buf[*buf_pos])) - ++*buf_pos; - //check for leading \n token - if (buf[*buf_pos] == '\n') { - ++*buf_pos; - token_set(&parser->token, TOK_NEWLINE, "\n"); - return 1; + char backed = 0, quoted = 0, commented = 0; + + //eat separators (" ",\t, \v) and comment + for (; *buf_pos < buf_size; ++*buf_pos) { + if (commented && buf[*buf_pos] == '#') + ; + else if (is_sep(buf[*buf_pos])) continue; + else if (buf[*buf_pos] == '#') commented = 1; + else break; + } + //eat comment + while (*buf_pos < buf_size && buf[*buf_pos] == '#') + while (*buf_pos < buf_size && buf[*buf_pos] == '\n') + ++*buf_pos; + //check if first chars is an operator + for (register int i = 0; operators[i].id != TOK_NONE; ++i) + if (!strncmp(buf + *buf_pos, operators[i].str, strlen(operators[i].str))) { + *buf_pos += strlen(operators[i].str); + token_set(&lexer->token, operators[i].id, operators[i].str); + return 1; } + // Rationale: Search end of token //cut a token token_start = token_pos = *buf_pos; - for (; !end_found && token_pos < buf_size; ++token_pos) - if (backed) - backed = 0; - else if (!quoted && (buf[token_pos] == '\n' || is_sep(buf[token_pos]))) - { end_found = 1; break; } - else if (!quoted && is_quote(buf[token_pos])) - quoted = buf[token_pos]; - else if (quoted && buf[token_pos] == quoted) - quoted = 0; - else if (!backed && buf[token_pos] == '\\') - backed = 1; + for (; !end_found && token_pos < buf_size; ++token_pos) { + if (backed) backed = 0; + else if (commented && buf[token_pos] == '\n') commented = 0; + else if (commented) continue; + else if (buf[token_pos] == '#') commented = 1; + else if (is_sep(buf[token_pos])) end_found = 1; + else if (!quoted && is_quote(buf[token_pos])) quoted = buf[token_pos]; + else if (quoted && buf[token_pos] == quoted) quoted = 0; + else if (!backed && buf[token_pos] == '\\') backed = 1; + else for (register int i = 0; operators[i].id != TOK_NONE; ++i) + if (!strncmp(buf + token_pos, operators[i].str, strlen(operators[i].str))) + { end_found = 1; break; } + if (end_found) break; + } if (!end_found) return 0; - parser->buf_pos = token_pos; - printf("cutted token: '%s'\n", - strndup(buf + token_start, token_pos - token_start)); - //check if it's a registered keyword - for (register int i = 0; keywords[i].str; ++i) - if (!strncmp(keywords[i].str, buf + token_start, - token_pos - token_start)) { - token_set(&parser->token, keywords[i].id, keywords[i].str); - printf("reconized token: %d (%s)\n", keywords[i].id, keywords[i].str); - return 1; - } - //althought this token is a word - token_set(&parser->token, TOK_WORD, - strndup(buf + token_start, token_pos - token_start)); - printf("reconized token (WORD): %d (%s)\n", - parser->token.id, parser->token.str); + lexer->buf_pos = token_pos; //update real lexer buffer + token_set(&lexer->token, TOK_CONTEXT, + strndup(buf + token_start, token_pos - token_start)); return 1; } +/* int parser_reconition() */ +/* { */ +/* //check if it's a registered keyword */ +/* for (register int i = 0; keywords[i].str; ++i) */ +/* if (!strncmp(keywords[i].str, buf + token_start, */ +/* token_pos - token_start)) { */ +/* token_set(&lexer->token, keywords[i].id, keywords[i].str); */ +/* /\* printf("reconized token: %d (%s)\n", keywords[i].id, keywords[i].str); *\/ */ +/* return 1; */ +/* } */ +/* return 0; */ +/* } */ +/* //check if it's a IONUMBER token */ +/* if (isdigitstr(str)) */ +/* token_set(&lexer->token, TOK_NUMBER, str); */ diff --git a/src/parser/parser.c b/src/parser/parser.c index d480f52..eb3e5ef 100644 --- a/src/parser/parser.c +++ b/src/parser/parser.c @@ -5,27 +5,41 @@ ** Login ** ** Started on Wed Aug 2 00:56:07 2006 Seblu -** Last update Sat Aug 19 01:30:25 2006 Seblu +** Last update Tue Aug 22 19:10:23 2006 Seblu */ #include #include #include +#include #include "parser.h" #include "../common/mem.h" #include "../shell/shell.h" #include "../readline/readline.h" /* -** Declaration +** ============ +** DECLARATIONS +** ============ */ +/* +** Define is parser is run for DEBBUGING +*/ +#define DEBUG_PARSER 1 + +static ts_ast_node *regnode(ts_parser *parser, ts_ast_node *node); + /*! -** Parse a line +** Parse an input, following the Grammar rule input +** input: list '\n' +** list EOF +** | '\n' +** | EOF ** -** @param parser +** @param parser parser struct ** -** @return +** @return parent ast node, for execution */ static ts_ast_node *parse_input(ts_parser *parser); @@ -33,8 +47,28 @@ static ts_ast_node *parse_list(ts_parser *parser); static ts_ast_node *parse_andor(ts_parser *parser); +static ts_ast_node *parse_pipeline(ts_parser *parser); + +static ts_ast_node *parse_command(ts_parser *parser); + +/*! +** Notify a parse error +** +** @param parser parser where error appear +** @param t token near of the error +*/ +static void parse_error(ts_parser *parser, ts_token t); + +#if DEBUG_PARSER==1 +# define debugmsg(msg) fprintf(stderr, "debug: %s\n", (msg)) +#else +# define debugmsg(msg) +#endif + /* -** Implemantation +** =========== +** DEFINITIONS +** =========== */ ts_parser *parser_init(FILE *fs) @@ -42,92 +76,151 @@ ts_parser *parser_init(FILE *fs) ts_parser *new; secmalloc(new, sizeof (ts_parser)); - fflush(fs); - new->fs = fs; - lexer_reset(new); + new->lexer = lexer_init(fs); + new->error = 0; + new->regnodes = NULL; + new->regsize = new->regpos = 0; return new; } -void parse_error(ts_parser *parser, ts_token t) +static ts_ast_node *regnode(ts_parser *parser, ts_ast_node *node) +{ + if (!node) + return node; + if (parser->regpos >= parser->regsize) { + parser->regsize += 50; + secrealloc(parser->regnodes, parser->regnodes, + parser->regsize * sizeof (ts_ast_node)); + } + parser->regnodes[parser->regpos] = node; + ++parser->regpos; + return node; +} + +static void parse_error(ts_parser *parser, ts_token t) { - printf("%s: syntax error near unexpected token `%s'\n", - shell->name, t.str); - parser->status = PARSE_ERROR; + debugmsg("parse_error"); + fprintf(stderr, "%s: syntax error near unexpected token `%s'\n", + shell->name, t.str); + parser->error = 1; shell->status = ERROR_PARSE; + if (parser->regnodes) + for (register int i = 0; parser->regnodes[i]; ++i) + ast_destruct(parser->regnodes[i]); + longjmp(parser->stack, 1); } ts_ast_node *parse(ts_parser *parser) { - lexer_reset(parser); - parser->status = PARSE_OK; + lexer_start(parser->lexer); + parser->regpos = 0; + parser->error = 0; + // prevent of too big register ast size + if (parser->regsize >= 200) + secrealloc(parser->regnodes, parser->regnodes, + (parser->regsize = 50) * sizeof (ts_ast_node)); + if (setjmp(parser->stack)) + return NULL; //test lexer mode while (1) { ts_token tok; - tok = lexer_gettoken(parser); + tok = lexer_gettoken(parser->lexer); if (tok.id == TOK_EOF) exit(42); if (tok.id == TOK_NEWLINE) - lexer_reset(parser); + lexer_start(parser->lexer); + printf("Returned token: %d [%s]\n", tok.id, tok.str); } return parse_input(parser); } static ts_ast_node *parse_input(ts_parser *parser) { - ts_token cur_token; - ts_ast_node *buf; + ts_token token; + ts_ast_node *buf; - cur_token = lexer_gettoken(parser); - if (cur_token.id == TOK_EOF) + debugmsg("parse_input"); + token = lexer_lookahead(parser->lexer); + if (token.id == TOK_EOF) return NULL; - if (cur_token.id == TOK_NEWLINE) - return ast_sep_create(NULL, NULL); + if (token.id == TOK_NEWLINE) { + token = lexer_gettoken(parser->lexer); + return NULL; + } buf = parse_list(parser); - cur_token = lexer_gettoken(parser); - if (cur_token.id != TOK_EOF || cur_token.id != TOK_NEWLINE) - parse_error(parser, cur_token); + token = lexer_gettoken(parser->lexer); + if (token.id != TOK_EOF || token.id != TOK_NEWLINE) + parse_error(parser, token); return buf; } static ts_ast_node *parse_list(ts_parser *parser) { - ts_token next_token; - ts_ast_node *lhs; -/* ts_ast_node *rhs; */ + ts_token token; + ts_ast_node *lhs; + ts_ast_node *rhs; + debugmsg("parse_list"); lhs = parse_andor(parser); - next_token = lexer_gettoken(parser); -/* if (next_token.id == TOK_SEP) { */ -/* lhs = parse_andor(parser); */ -/* } */ -/* else if (next_token.id == TOK_SEPAND) { */ -/* parse_error(parser, next_token); */ -/* /\* return buf; *\/ */ -/* } */ -/* parse_error(parser, next_token); */ -/* return ; */ - return NULL; + token = lexer_lookahead(parser->lexer); + if (token.id == TOK_SEP || token.id == TOK_SEPAND) { + lexer_gettoken(parser->lexer); + rhs = parse_list(parser); + if (token.id == TOK_SEP) + return regnode(parser, ast_sep_create(lhs, rhs)); + else + return regnode(parser, ast_sepand_create(lhs, rhs)); + } + return lhs; } static ts_ast_node *parse_andor(ts_parser *parser) { - parser = parser; - return NULL; + ts_token token; + ts_ast_node *lhs; + ts_ast_node *rhs; + + debugmsg("parse_andor"); + lhs = parse_pipeline(parser); + token = lexer_lookahead(parser->lexer); + if (token.id == TOK_AND || token.id == TOK_OR) { + lexer_gettoken(parser->lexer); + rhs = parse_andor(parser); + if (token.id == TOK_AND) + return regnode(parser, ast_and_create(lhs, rhs)); + else + return regnode(parser, ast_or_create(lhs, rhs)); + } + return lhs; } -/* static ts_ast_node *parse_pipeline(ts_parser *parser) */ -/* { */ -/* parser=parser; */ -/* return NULL; */ -/* } */ +static ts_ast_node *parse_pipeline(ts_parser *parser) +{ + ts_token token; + ts_ast_node *lhs; + int banged = 0; + + debugmsg("parse_pipeline"); + token = lexer_lookahead(parser->lexer); + if (token.id == TOK_BANG) { + lexer_gettoken(parser->lexer); + banged = 1; + } + lhs = parse_command(parser); + return lhs; +} -/* static ts_ast_node *parse_command(ts_parser *parser) */ -/* { */ -/* parser=parser; */ -/* return NULL; */ -/* } */ +static ts_ast_node *parse_command(ts_parser *parser) +{ + ts_token token; + + + token = lexer_lookahead(parser->lexer); + //if (token.id == TOK_WORD) + return NULL; +} /* static ts_ast_node *parse_simplecommand(ts_parser *parser) */ /* { */ diff --git a/src/parser/parser.h b/src/parser/parser.h index 0e6659b..cef61bf 100644 --- a/src/parser/parser.h +++ b/src/parser/parser.h @@ -5,20 +5,27 @@ ** Login ** ** Started on Wed Aug 2 00:49:50 2006 Seblu -** Last update Sat Aug 19 01:35:31 2006 Seblu +** Last update Wed Aug 23 02:33:38 2006 Seblu */ -#include +#include #include "../ast/ast.h" #ifndef PARSER_H_ # define PARSER_H_ -typedef enum e_token +typedef enum e_token { + //token free-context recognition + TOK_NONE, + TOK_NEWLINE, + TOK_NUMBER, + TOK_EOF, TOK_AND, TOK_OR, TOK_DSEMI, + TOK_LESS, + TOK_GREAT, TOK_DLESS, TOK_DGREAT, TOK_LESSAND, @@ -26,6 +33,10 @@ typedef enum e_token TOK_LESSGREAT, TOK_DLESSDASH, TOK_CLOBBER, + TOK_CONTEXT, + TOK_WORD, + //token context-sensitive recognition + TOK_ASSIGNMENT, TOK_IF, TOK_THEN, TOK_ELSE, @@ -42,40 +53,51 @@ typedef enum e_token TOK_LBRACE, TOK_RBRACE, TOK_BANG, - TOK_NEWLINE, TOK_SEP, TOK_SEPAND, - TOK_WORD, - TOK_EOF, - TOK_BEGIN, - TOK_NONE, - TOK_ERR } te_tokenid; -typedef struct s_token +typedef struct s_token { te_tokenid id; const char *str; } ts_token; -typedef enum e_parser_status +typedef enum e_lexer_status { - PARSE_OK, - PARSE_ERROR, - PARSE_END - } te_parser_status; + LEXER_READY = 1, + LEXER_END = 2, + } te_lexer_status; -typedef struct s_parser +typedef struct s_lexer { - te_parser_status status; + te_lexer_status status; ts_token token; FILE *fs; char *buf; size_t buf_size; size_t buf_pos; - size_t tok_start; +} ts_lexer; + +typedef struct s_parser +{ + int error; + ts_lexer *lexer; + jmp_buf stack; + ts_ast_node **regnodes; + size_t regsize; + size_t regpos; } ts_parser; + +/*! +** Free the string of a token if is a word (dynamically allocated) +** +** @param token a token struct type (not a pointer) +*/ +#define token_free(token) if ((token).id == TOK_WORD && (token).str) \ + free((char*)(token).str) + /* ** ============== ** FILE: parser.c @@ -91,14 +113,6 @@ typedef struct s_parser */ ts_parser *parser_init(FILE *fs); -/*! -** Notify a parse error -** -** @param parser parser where error appear -** @param t token near of the error -*/ -void parse_error(ts_parser *parser, ts_token t); - /*! ** Do a parse pass ** @@ -115,32 +129,43 @@ ts_ast_node *parse(ts_parser *parser); */ /*! -** Set (or reset) the lexer +** Lexer initialization +** +** @param fs file stream to read +** +** @return the new struct +*/ +ts_lexer *lexer_init(FILE *fs); + +/*! +** Start a new lexical recognition ** This must be call by parser before each parse start ** This function is necessarity to correctly show the prompt ** -** @param parser lexer to reset +** @param lexer lexer to set in starting block +** +** @return return if lexer is ready to start or not */ -void lexer_reset(ts_parser *parser); +int lexer_start(ts_lexer *lexer); /*! ** Return the next token and destroy it ** @warning The token MUST be freed ! ** -** @param parser parser/lexer structure +** @param lexer lexer structure ** ** @return the next token */ -ts_token lexer_gettoken(ts_parser *parser); +ts_token lexer_gettoken(ts_lexer *lexer); /*! ** Return the next token without destruction of it. ** @warning The token string MUST NOT be freed ! ** -** @param parser parser/lexer structure +** @param lexer lexer structure ** ** @return the look ahead token */ -ts_token lexer_lookahead(ts_parser *parser); +ts_token lexer_lookahead(ts_lexer *lexer); #endif diff --git a/src/shell/shell.h b/src/shell/shell.h index 884b2aa..b2b53d7 100644 --- a/src/shell/shell.h +++ b/src/shell/shell.h @@ -5,7 +5,7 @@ ** Login ** ** Started on Sun Jul 16 20:03:53 2006 Seblu -** Last update Sat Aug 19 01:45:54 2006 Seblu +** Last update Wed Aug 23 18:38:11 2006 Seblu */ #ifndef SHELL_H_ @@ -13,7 +13,8 @@ # include # include -# include "../opt/opt.h" +# include "../alias/alias.h" +# include "../option/option.h" static const int ERROR_PARSE = 258; static const int ERROR_FORK = 128; @@ -30,7 +31,8 @@ typedef struct s_shell /* struct s_var *vars; */ /* struct s_func *funcs; */ /* struct s_history *history; */ - ts_opt *opt; + ts_aliases *aliases; + ts_options *options; char *name; int status; } ts_shell; @@ -40,6 +42,6 @@ void shell_destroy(ts_shell *sh); const char *get_prompt(te_prompt_type pty); -ts_shell *shell; +extern ts_shell *shell; #endif /* !SHELL_H_ */ diff --git a/src/shell/shell_entry.c b/src/shell/shell_entry.c index 991ff77..460fa5b 100644 --- a/src/shell/shell_entry.c +++ b/src/shell/shell_entry.c @@ -5,7 +5,7 @@ ** Login ** ** Started on Mon Apr 10 23:57:28 2006 Seblu -** Last update Thu Aug 3 07:01:52 2006 Seblu +** Last update Wed Aug 23 18:40:08 2006 Seblu */ #include @@ -36,17 +36,17 @@ int main(int argc, char *argv[]) // shell initialization shell = shell_init(argv[0]); // parse argv - opt_parser(argc, argv, shell->opt); + option_parser(shell->options, argc, argv); // shell parser init parser = parser_init(stdin); // parse and execute stdin stream do { ast = parse(parser); - if (parser->status == PARSE_OK) + if (!parser->error) exec_ast(ast); ast_destruct(ast); } - while (parser->status != PARSE_END); + while (parser->lexer->status != LEXER_END); return shell->status; } diff --git a/src/shell/shell_init.c b/src/shell/shell_init.c index e30c241..2b3cc3f 100644 --- a/src/shell/shell_init.c +++ b/src/shell/shell_init.c @@ -5,7 +5,7 @@ ** Login ** ** Started on Sun Jul 16 20:11:09 2006 Seblu -** Last update Thu Aug 3 05:28:33 2006 Seblu +** Last update Wed Aug 23 18:41:10 2006 Seblu */ #include @@ -15,7 +15,7 @@ #include #include #include "shell.h" -#include "../opt/opt.h" +#include "../option/option.h" #include "../common/mem.h" #include "../common/common.h" @@ -36,7 +36,8 @@ ts_shell *shell_init(const char *argv0) /* new->vars = NULL; */ /* new->funcs = NULL; */ /* new->history = NULL; */ - new->opt = opt_init(); + new->aliases = alias_init(); + new->options = option_init(); /* if (!pwd_isgood()) */ /* { */ /* var_setenv("PWD", (tmp = var_getcwd()), 1); */ -- GitLab