diff --git a/src/Makefile.am b/src/Makefile.am index 39089adadd3fc0943696e097a78e763588f7dec8..c80bcdadb508f506837d35a275b0e933f459b837 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -23,8 +23,9 @@ bin_PROGRAMS=42sh ast/ast_until.c \ ast/ast_while.c \ common/common.h \ + common/constant.h \ common/isdigitstr.c \ - common/mem.h \ + common/macro.h \ common/strmerge.c \ common/strvmerge.c \ common/strndup.c \ diff --git a/src/alias/alias.c b/src/alias/alias.c index 2216285e1241d465f117d80197025e7e1ac4f470..732813831a9f31510d2594f74ae11716c5b34136 100644 --- a/src/alias/alias.c +++ b/src/alias/alias.c @@ -5,12 +5,12 @@ ** Login ** ** Started on Wed Aug 23 00:39:17 2006 Seblu -** Last update Wed Aug 23 18:47:59 2006 Seblu +** Last update Fri Aug 25 03:44:03 2006 Seblu */ #include #include "alias.h" -#include "../common/mem.h" +#include "../common/macro.h" static size_t step = 5; diff --git a/src/ast/ast.h b/src/ast/ast.h index 9b89df385559e0990b1066120e8549d27da6f300..687b112a2f6a02fab7ee8329fdd9016e2cfd40c7 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -5,16 +5,13 @@ ** Login ** ** Started on Sun Jul 30 04:40:03 2006 Seblu -** Last update Fri Aug 18 22:38:00 2006 Seblu +** Last update Fri Aug 25 03:47:41 2006 Seblu */ #ifndef AST_H_ # define AST_H_ -# include -# include -# include -# include +# include "../common/macro.h" typedef struct s_ast_node ts_ast_node; diff --git a/src/ast/ast_and.c b/src/ast/ast_and.c index 46058aea8a8d4cbcbbf4174c101be657c576c3b8..141610ede54b300000c3ef228018b3724b16542a 100644 --- a/src/ast/ast_and.c +++ b/src/ast/ast_and.c @@ -5,10 +5,9 @@ ** Login ** ** Started on Thu Aug 3 02:41:37 2006 Seblu -** Last update Fri Aug 18 20:40:35 2006 Seblu +** Last update Fri Aug 25 03:45:10 2006 Seblu */ -#include "../common/mem.h" #include "ast.h" ts_ast_node *ast_and_create(ts_ast_node *lhs, ts_ast_node *rhs) diff --git a/src/ast/ast_bang.c b/src/ast/ast_bang.c index 7ea0606ea736cfb933bd4db4ca2aa389f28e59b3..842ea29dbca345b8429e3c5193e8e72e9763dd74 100644 --- a/src/ast/ast_bang.c +++ b/src/ast/ast_bang.c @@ -5,10 +5,9 @@ ** Login ** ** Started on Thu Aug 3 02:41:37 2006 Seblu -** Last update Fri Aug 18 20:43:52 2006 Seblu +** Last update Fri Aug 25 03:45:26 2006 Seblu */ -#include "../common/mem.h" #include "ast.h" ts_ast_node *ast_bang_create(ts_ast_node *child) diff --git a/src/ast/ast_case.c b/src/ast/ast_case.c index c7f6ed8baec8d87fa3832a6982608f803ce6b9a5..11d20ef040560a92368bd10ee499e260a88547b6 100644 --- a/src/ast/ast_case.c +++ b/src/ast/ast_case.c @@ -5,10 +5,9 @@ ** Login ** ** Started on Thu Aug 3 02:41:37 2006 Seblu -** Last update Fri Aug 18 22:32:35 2006 Seblu +** Last update Fri Aug 25 03:45:34 2006 Seblu */ -#include "../common/mem.h" #include "ast.h" ts_ast_node *ast_case_create(char *word) diff --git a/src/ast/ast_for.c b/src/ast/ast_for.c index dada22f07bbde83c4e16381b854fd363e2dcbf00..3f0c86685f1f83dfe63c531bd5f03370ca4ceff9 100644 --- a/src/ast/ast_for.c +++ b/src/ast/ast_for.c @@ -5,10 +5,9 @@ ** Login ** ** Started on Thu Aug 3 02:41:37 2006 Seblu -** Last update Fri Aug 18 20:38:08 2006 Seblu +** Last update Fri Aug 25 03:45:55 2006 Seblu */ -#include "../common/mem.h" #include "ast.h" ts_ast_node *ast_for_create(char *varname, diff --git a/src/ast/ast_funcdec.c b/src/ast/ast_funcdec.c index 21d548dbadadf067211c2a3e0961479f71845ea3..7b5f90184a61a84d2efadf7dab8ee764cea5c51b 100644 --- a/src/ast/ast_funcdec.c +++ b/src/ast/ast_funcdec.c @@ -5,10 +5,9 @@ ** Login ** ** Started on Thu Aug 3 02:41:37 2006 Seblu -** Last update Fri Aug 18 20:43:15 2006 Seblu +** Last update Fri Aug 25 03:46:54 2006 Seblu */ -#include "../common/mem.h" #include "ast.h" ts_ast_node *ast_funcdec_create(char *name, ts_ast_node *body) diff --git a/src/ast/ast_if.c b/src/ast/ast_if.c index ba16569dec89ac4082f9efce8f591ec1a6312ab0..4cdc90239d6adf69b80ff59fcfde0e6b17bbc1da 100644 --- a/src/ast/ast_if.c +++ b/src/ast/ast_if.c @@ -5,10 +5,9 @@ ** Login ** ** Started on Thu Aug 3 02:41:37 2006 Seblu -** Last update Fri Aug 18 20:37:47 2006 Seblu +** Last update Fri Aug 25 03:46:10 2006 Seblu */ -#include "../common/mem.h" #include "ast.h" ts_ast_node *ast_if_create(ts_ast_node *cond, diff --git a/src/ast/ast_or.c b/src/ast/ast_or.c index 71d2ec574da1719ae4a9f86405b15a18e89a8fb2..d48948db02a4df92cbe552515396fb3ea2d11e10 100644 --- a/src/ast/ast_or.c +++ b/src/ast/ast_or.c @@ -5,10 +5,9 @@ ** Login ** ** Started on Thu Aug 3 02:41:37 2006 Seblu -** Last update Fri Aug 18 20:40:50 2006 Seblu +** Last update Fri Aug 25 03:46:27 2006 Seblu */ -#include "../common/mem.h" #include "ast.h" ts_ast_node *ast_or_create(ts_ast_node *lhs, ts_ast_node *rhs) diff --git a/src/ast/ast_pipe.c b/src/ast/ast_pipe.c index 28ddc7a89ae5b1f6ab1cd52637725e91941d3430..9c8a5e462e3942cfd5ddac5c4a2f5d2175ba55ab 100644 --- a/src/ast/ast_pipe.c +++ b/src/ast/ast_pipe.c @@ -5,10 +5,9 @@ ** Login ** ** Started on Thu Aug 3 02:41:37 2006 Seblu -** Last update Fri Aug 18 20:44:37 2006 Seblu +** Last update Fri Aug 25 03:46:33 2006 Seblu */ -#include "../common/mem.h" #include "ast.h" ts_ast_node *ast_pipe_create(ts_ast_node *lhs, ts_ast_node *rhs) diff --git a/src/ast/ast_sep.c b/src/ast/ast_sep.c index 6215e5242aa65c347d5e2b4056eff37bc434cd7d..9b927b633f54ec485f632524f18fd334df4317e2 100644 --- a/src/ast/ast_sep.c +++ b/src/ast/ast_sep.c @@ -5,10 +5,9 @@ ** Login ** ** Started on Thu Aug 3 02:41:37 2006 Seblu -** Last update Fri Aug 18 20:48:47 2006 Seblu +** Last update Fri Aug 25 03:46:42 2006 Seblu */ -#include "../common/mem.h" #include "ast.h" ts_ast_node *ast_sep_create(ts_ast_node *lhs, ts_ast_node *rhs) diff --git a/src/ast/ast_sepand.c b/src/ast/ast_sepand.c index 41b103024728787587ad3659cb57e30f341b8adc..50b81b55af6f6cff273a9c9c34aa9bec342d25d7 100644 --- a/src/ast/ast_sepand.c +++ b/src/ast/ast_sepand.c @@ -5,10 +5,9 @@ ** Login ** ** Started on Thu Aug 3 02:41:37 2006 Seblu -** Last update Fri Aug 18 20:49:02 2006 Seblu +** Last update Fri Aug 25 03:48:01 2006 Seblu */ -#include "../common/mem.h" #include "ast.h" ts_ast_node *ast_sepand_create(ts_ast_node *lhs, ts_ast_node *rhs) diff --git a/src/ast/ast_subshell.c b/src/ast/ast_subshell.c index 5679df7555f1af3ff5d01601f705adcaedce3456..e2c75469ffa88a28076529cb1196ba22eaa95035 100644 --- a/src/ast/ast_subshell.c +++ b/src/ast/ast_subshell.c @@ -5,10 +5,9 @@ ** Login ** ** Started on Thu Aug 3 02:41:37 2006 Seblu -** Last update Fri Aug 18 20:42:28 2006 Seblu +** Last update Fri Aug 25 03:48:09 2006 Seblu */ -#include "../common/mem.h" #include "ast.h" ts_ast_node *ast_subshell_create(ts_ast_node *child) diff --git a/src/ast/ast_until.c b/src/ast/ast_until.c index 7d355332165a836e7ec37750b8af638dd30f9baf..f0a0968d27432cc1e6cbb22f7a8113bca567f40a 100644 --- a/src/ast/ast_until.c +++ b/src/ast/ast_until.c @@ -5,10 +5,9 @@ ** Login ** ** Started on Thu Aug 3 02:41:37 2006 Seblu -** Last update Fri Aug 18 20:39:25 2006 Seblu +** Last update Fri Aug 25 03:48:15 2006 Seblu */ -#include "../common/mem.h" #include "ast.h" ts_ast_node *ast_until_create(ts_ast_node *cond, ts_ast_node *exec) diff --git a/src/ast/ast_while.c b/src/ast/ast_while.c index 098332724228ed4ef3fbd93d9186d7ec3bf22e23..e8c60eb36ddbb339488215d8252b540f6b0886e6 100644 --- a/src/ast/ast_while.c +++ b/src/ast/ast_while.c @@ -5,10 +5,9 @@ ** Login ** ** Started on Thu Aug 3 02:41:37 2006 Seblu -** Last update Fri Aug 18 20:39:02 2006 Seblu +** Last update Fri Aug 25 03:48:21 2006 Seblu */ -#include "../common/mem.h" #include "ast.h" ts_ast_node *ast_while_create(ts_ast_node *cond, ts_ast_node *exec) diff --git a/src/common/common.h b/src/common/common.h index f6c92edf62d17ed1423c45430e1e00ec43e24c78..cef48215cc8fbec5911f7766a7c5a9a3068b2879 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 Tue Aug 22 22:41:29 2006 Seblu +** Last update Fri Aug 25 03:31:29 2006 Seblu */ #ifndef COMMON_H_ diff --git a/src/common/constant.h b/src/common/constant.h new file mode 100644 index 0000000000000000000000000000000000000000..9b76b22a9faaddc92934dc62b990fa167bab26cc --- /dev/null +++ b/src/common/constant.h @@ -0,0 +1,28 @@ +/* +** constant.h for 42sh +** +** Made by Seblu +** Login +** +** Started on Fri Aug 25 03:39:03 2006 Seblu +** Last update Fri Aug 25 07:34:15 2006 Seblu +*/ + +#ifndef CONSTANT_H_ +# define CONSTANT_H_ + +typedef enum e_error + { + ERROR_PARSE = 258, + ERROR_FORK = 128, + ERROR_REDIR = 1, + ERROR_MEM = 42, + } te_error; + +typedef enum e_prompt { + PROMPT_PS1 = 1, + PROMPT_PS2 = 2, + PROMPT_PS4 = 4 +} te_prompt; + +#endif diff --git a/src/common/macro.h b/src/common/macro.h new file mode 100644 index 0000000000000000000000000000000000000000..2e835aa0c6f88b501448d1721591b17f4e63d904 --- /dev/null +++ b/src/common/macro.h @@ -0,0 +1,24 @@ +/* +** macro.h for 42sh +** +** Made by Seblu +** Login +** +** Started on Fri Aug 25 03:32:54 2006 Seblu +** Last update Fri Aug 25 03:42:43 2006 Seblu +*/ + +#ifndef MACRO_H_ +# define MACRO_H_ + +# include +# include +# include "constant.h" + +# define secmalloc(name, size) if (!(name = malloc(size))) exit(ERROR_MEM) +# define secrealloc(ret, name, size) if (!(ret = realloc(name, size))) exit(ERROR_MEM) +# define secstrdup(ret, str) if (!(ret = strdup(str))) exit(ERROR_MEM) + +# define isinteractive() (isatty(STDOUT_FILENO) && isatty(STDERR_FILENO)) + +#endif diff --git a/src/common/mem.h b/src/common/mem.h deleted file mode 100644 index 1356a47499d0831340de78568dccfec316accebc..0000000000000000000000000000000000000000 --- a/src/common/mem.h +++ /dev/null @@ -1,22 +0,0 @@ -/* -** mem.h for 42sh -** -** Made by Seblu -** Login -** -** Started on Sun Jul 30 03:35:39 2006 Seblu -** Last update Sun Jul 30 03:42:49 2006 Seblu -*/ - -#ifndef MACRO_H_ -# define MACRO_H_ - -#include - -static const int MEM_ERROR = 42; - -# define secmalloc(name, size) if (!(name = malloc(size))) exit(MEM_ERROR) -# define secrealloc(ret, name, size) if (!(ret = realloc(name, size))) exit(MEM_ERROR) -# define secstrdup(ret, str) if (!(ret = strdup(str))) exit(MEM_ERROR) - -#endif diff --git a/src/common/strmerge.c b/src/common/strmerge.c index 67bb974199f3b5af99ed3ab923394a65d483c353..d82b7954ea9629aeac0ff54a200c59295ffd0893 100644 --- a/src/common/strmerge.c +++ b/src/common/strmerge.c @@ -5,12 +5,12 @@ ** Login ** ** Started on Tue May 16 21:23:02 2006 Seblu -** Last update Thu Aug 3 05:29:21 2006 Seblu +** Last update Fri Aug 25 03:48:39 2006 Seblu */ #include #include -#include "mem.h" +#include "macro.h" char *strmerge(int n, const char *s1, ...) { diff --git a/src/common/strndup.c b/src/common/strndup.c index f834378bd1833efd8f604e21d7c02172d36c1c6b..0342bcf045957ec513fccc8beaf5d7831ba1cb52 100644 --- a/src/common/strndup.c +++ b/src/common/strndup.c @@ -5,12 +5,12 @@ ** Login ** ** Started on Thu Aug 3 05:56:28 2006 Seblu -** Last update Thu Aug 3 05:58:42 2006 Seblu +** Last update Fri Aug 25 03:49:08 2006 Seblu */ #include #include -#include "mem.h" +#include "macro.h" char *strndup(const char *str, size_t n) { diff --git a/src/common/strvmerge.c b/src/common/strvmerge.c index c1043deafe41e28a5c58421103cb2155313a3833..330fbf88e6992e897c7907cf6132bc93cf7cdae0 100644 --- a/src/common/strvmerge.c +++ b/src/common/strvmerge.c @@ -5,11 +5,11 @@ ** Login ** ** Started on Sun Jul 30 04:03:35 2006 Seblu -** Last update Thu Aug 3 05:29:38 2006 Seblu +** Last update Fri Aug 25 03:48:47 2006 Seblu */ #include -#include "mem.h" +#include "macro.h" char *strvmerge(const char *const *vtable) { diff --git a/src/option/option.c b/src/option/option.c index a11956fcaf1676254d496901c088d36bfb32e8d2..9c7b04650d0d181e4acae081b0fe4add2f673ccf 100644 --- a/src/option/option.c +++ b/src/option/option.c @@ -5,7 +5,7 @@ ** Login ** ** Started on Tue Mar 21 19:00:38 2006 Seblu -** Last update Wed Aug 23 18:37:38 2006 Seblu +** Last update Fri Aug 25 03:49:21 2006 Seblu */ /* @@ -17,7 +17,7 @@ #include #include "option.h" #include "../shell/shell.h" -#include "../common/mem.h" +#include "../common/macro.h" static const char *opts_table[NBR_OPTION] = { diff --git a/src/parser/lexer.c b/src/parser/lexer.c index 8d0995ba16a82b6a11976f27ba8113b46eef536e..0609bc0626e02d24c4940022a167ef5d4f1a9200 100644 --- a/src/parser/lexer.c +++ b/src/parser/lexer.c @@ -5,23 +5,24 @@ ** Login ** ** Started on Sun Jul 30 04:36:53 2006 Seblu -** Last update Wed Aug 23 18:05:56 2006 Seblu +** Last update Fri Aug 25 15:16:23 2006 Seblu */ #include #include #include +#include #include "parser.h" #include "../shell/shell.h" #include "../readline/readline.h" #include "../common/common.h" -#include "../common/mem.h" +#include "../common/macro.h" /* ** 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. +** - Quotes are chars which must be return entierrely. ** - Others are chars considered like words. */ @@ -31,55 +32,72 @@ ** ============ */ -static ts_token operators[] = +// Order is very important for correct recognition ! +static const ts_token operators[] = { - {TOK_NEWLINE, "\n"}, - {TOK_AND, "&&"}, - {TOK_OR, "||"}, - {TOK_DSEMI, ";;"}, - {TOK_LESS, "<"}, - {TOK_GREAT, ">"}, - {TOK_DLESS, "<<"}, - {TOK_DGREAT, ">>"}, - {TOK_LESSAND, "<&"}, - {TOK_GREATAND, ">&"}, - {TOK_LESSGREAT, "<>"}, - {TOK_DLESSDASH, "<<-"}, - {TOK_CLOBBER, ">|"}, - {TOK_SEP, ";"}, - {TOK_SEPAND, "&"}, - {TOK_NONE, NULL} + {TOK_NEWLINE, "\n", 1}, + {TOK_AND, "&&", 2}, + {TOK_SEPAND, "&", 1}, + {TOK_OR, "||", 2}, + {TOK_PIPE, "|", 1}, + {TOK_DSEMI, ";;", 2}, + {TOK_SEP, ";", 1}, + {TOK_DLESSDASH, "<<-", 3}, + {TOK_DLESS, "<<", 2}, + {TOK_LESSGREAT, "<>", 2}, + {TOK_LESSAND, "<&", 2}, + {TOK_LESS, "<", 1}, + {TOK_DGREAT, ">>", 2}, + {TOK_GREATAND, ">&", 2}, + {TOK_CLOBBER, ">|", 2}, + {TOK_GREAT, ">", 1}, + {TOK_NONE, NULL, 0} }; -/* 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} */ -/* }; */ +typedef struct s_quote +{ + const char *start; + const size_t lenstart; + const char *stop; + const size_t lenstop; +} ts_quote; + +static const ts_quote quotes[] = + { + {"\"", 1, "\"", 1}, + {"'", 1, "'", 1}, + {"`", 1, "`", 1}, + {"${", 2, "}", 1}, + {"$(", 2, ")", 1}, + {"$((", 2, "))", 2}, + {NULL, 0, NULL, 0}, + }; /*! -** Return a predicat about c is a quote +** Check if @arg buf + *buf_pos point on the start of quote sequence. +** @warning Recognition start at buf + *buf_pos ! ** -** @param c Must be a character +** @param buf a string buffer +** @param buf_pos position in the buffer, which is incremented if found to point on +** the last char of the quote ! +** @param quote quote type found +** +** @return true (!0) if a quote is found, else false (0) +*/ +static int is_quote_start(const char *buf, size_t *buf_pos, const ts_quote **quote); + +/*! +** Check if @arg buf + *buf_pos point on the stop of quote sequence. +** @warning Recognition start at buf + *buf_pos ! +** +** @param buf a string buffer +** @param buf_pos position in the buffer, which is incremented if found to point on +** the last char of the quote ! +** @param quote quote type to found ** -** @return true if c is a quote +** @return true (!0) if a quote is found, else false (0) */ -#define is_quote(c) ((c) == '"' || (c) == '\'' || (c) == '`') +static int is_quote_stop(const char *buf, size_t *buf_pos, const ts_quote *quote); /*! ** Return a predicat about c is a separator @@ -91,20 +109,42 @@ static ts_token operators[] = #define is_sep(c) ((c) == ' ' || (c) == '\t' || (c) == '\v') /*! -** Call readline while it's necessary to reconize a token. +** Check if the buffer point to an operator. Il it's true and buf_pos is +** not NULL, *buf_pos is correctly incremented to point on the next token +** @warning Recgnition start at buf ! +** +** @param buf a string buffer where recognition start +** @param buf_pos buffer position to increment correctly if operator is found +** @param token reconized token operator +** +** @return true (!0) if find, else false (0) +*/ +static int is_operator(const char *buf, size_t *buf_pos, ts_token *token); + +/*! +** Read lexer's stream, and return the next token. ** ** @param lex lexer struct */ -static void lexer_eat(ts_lexer *lex); +static void lexer_eattoken(ts_lexer *lex); + +/*! +** This function is only call when the end of a line occur in +** a quote or after a backslash +** +** @param lexer lexer struct +** +** @return 1 if can read a line, 0 if eof +*/ +static int lexer_eatline(ts_lexer *lexer); /*! -** Cut and reconize a token. +** Cut a token in one or more line. ** ** @param lexer lexer struct ** -** @return 1, if someting is reconized, else 0 */ -static int lexer_reconize(ts_lexer *lexer); +static int lexer_cut(ts_lexer *lexer); /*! ** Correctly set a token. In first, it call macro token_free to @@ -132,156 +172,177 @@ ts_lexer *lexer_init(FILE *fs) new->fs = fs; new->buf = NULL; new->buf_size = new->buf_pos = 0; - new->status = LEXER_READY; + new->token.id = TOK_NONE; + new->token.str = NULL; + new->token.len = 0; + new->eof = 0; return new; } -int lexer_start(ts_lexer *lexer) -{ - 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_lookahead(ts_lexer *lexer) { if (lexer->token.id == TOK_NONE) - lexer_eat(lexer); + lexer_eattoken(lexer); return lexer->token; } ts_token lexer_gettoken(ts_lexer *lexer) { - ts_token buf; + ts_token buf = { TOK_EOF, "EOF", 3 }; - if (lexer->token.id == TOK_EOF) - return lexer->token; if (lexer->token.id == TOK_NONE) - lexer_eat(lexer); + lexer_eattoken(lexer); buf = lexer->token; lexer->token.id = TOK_NONE; lexer->token.str = NULL; return buf; } +void lexer_heredocument(ts_lexer *lexer) +{ + lexer = lexer; +} + static void token_set(ts_token *token, te_tokenid id, const char *s) { - token_free(*token); + if (token->id == TOK_WORD) + free((char*) token->str); token->id = id; token->str = s; + if (s) token->len = strlen(s); + else token->len = 0; } -static void lexer_eat(ts_lexer *lexer) +static void lexer_eattoken(ts_lexer *lexer) { - char *lbuf, *lbuf2; - - //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; - } - lexer->buf_pos = 0; + //if eof, set token EOF + if (lexer->eof) { + token_set(&lexer->token, TOK_EOF, "EOF"); + return; + } + //if last char was read free buffer + if (lexer->buf_size > 0 && lexer->buf_pos == lexer->buf_size) { + free(lexer->buf); + lexer->buf = NULL; + lexer->buf_size = 0; + } + //read a line if buf is empty + if (!lexer->buf_size && ((lexer->buf = readline(NULL)) != NULL)) { lexer->buf_size = strlen(lexer->buf); + lexer->buf_pos = 0; } - //read line while a token will not be reconized - 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); - } + //if eof is read, bye bye + if (lexer->buf == NULL) { + lexer->eof = 1; + token_set(&lexer->token, TOK_EOF, "EOF"); + return; } + //cut a slice of stream + while (!lexer_cut(lexer)) + ;; //retry again } -/* 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_eatline(ts_lexer *lexer) +{ + char *buf, *buf2; -/* } */ + buf = lexer->buf; + assert(buf); + if (lexer->buf_size > 0 && buf[lexer->buf_size - 1] == '\n') + buf[lexer->buf_size - 1] = 0; + if (lexer->buf_size > 1 && buf[lexer->buf_size - 2] == '\\') + buf[lexer->buf_size - 2] = 0; + //show incomplet recognition prompt + show_prompt(PROMPT_PS2); + //retrieve a new line + if (!(buf2 = readline(NULL))) { + lexer->eof = 1; + return 0; + } + lexer->buf = strmerge(2, buf, buf2); + lexer->buf_size = strlen(lexer->buf); + free(buf); + free(buf2); + return 1; +} -static int lexer_reconize(ts_lexer *lexer) +static int lexer_cut(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; + size_t *buf_pos = &lexer->buf_pos, token_start, token_pos; int end_found = 0; - char backed = 0, quoted = 0, commented = 0; + char backed = 0, quoted = 0; + const ts_quote*quote; - //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; - } + // Rationale: Search begin of token + //eat separators (" ",\t, \v) + while (buf[*buf_pos] && is_sep(buf[*buf_pos])) + ++*buf_pos; //eat comment - while (*buf_pos < buf_size && buf[*buf_pos] == '#') - while (*buf_pos < buf_size && buf[*buf_pos] == '\n') + if (buf[*buf_pos] == '#') + while (buf[*buf_pos] && 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 + if (is_operator(buf + *buf_pos, buf_pos, &lexer->token)) + return 1; token_start = token_pos = *buf_pos; - 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; + // Rationale: Search end of token + for (; buf[token_pos]; ++token_pos) { + // backslah newline => eatline + if ((backed || quoted) && buf[token_pos] == '\n' && lexer_eatline(lexer)) + return 0; //new line added, you can try again + // backed, go to next char + else if (backed) backed = 0; + // check end of quoting + else if (quoted && is_quote_stop(buf, &token_pos, quote)) quoted = 0; + // quotin not ended ! + else if (quoted) continue; + // if backslash go in state backed 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 sep, a token was found ! + else if (is_sep(buf[token_pos])) end_found = 1; + // if it's an operator cut + else if (is_operator(buf + token_pos, NULL, NULL)) end_found = 1; + // check to start quoting + else if (!quoted && is_quote_start(buf, &token_pos, "e)) quoted = 1; if (end_found) break; } - if (!end_found) return 0; - lexer->buf_pos = token_pos; //update real lexer buffer - token_set(&lexer->token, TOK_CONTEXT, + lexer->buf_pos = token_pos; //update real lexer position buffer + token_set(&lexer->token, TOK_WORD, 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); */ +static int is_operator(const char *buf, size_t *buf_pos, ts_token *token) +{ + for (register int i = 0; operators[i].id != TOK_NONE; ++i) + if (!strncmp(buf, operators[i].str, operators[i].len)) { + if (buf_pos) + *buf_pos += operators[i].len; + if (token) + token_set(token, operators[i].id, operators[i].str); + return 1; + } + return 0; +} + +static int is_quote_start(const char *buf, size_t *buf_pos, const ts_quote **quote) +{ + for (register int i = 0; quotes[i].start; ++i) + if (!strncmp(buf + *buf_pos, quotes[i].start, quotes[i].lenstart)) { + *buf_pos += quotes[i].lenstart - 1; + if (quote) + *quote = quotes + i; + return 1; + } + return 0; +} + +static int is_quote_stop(const char *buf, size_t *buf_pos, const ts_quote *quote) +{ + if (!strncmp(buf + *buf_pos, quote->stop, quote->lenstop)) { + *buf_pos += quote->lenstop - 1; + return 1; + } + return 0; +} diff --git a/src/parser/parser.c b/src/parser/parser.c index eb3e5ef4c90329b985dbb6d86d205f8bf86b65e4..654f734a3d8fcf63184652de8a05cb47259e8a4c 100644 --- a/src/parser/parser.c +++ b/src/parser/parser.c @@ -5,7 +5,7 @@ ** Login ** ** Started on Wed Aug 2 00:56:07 2006 Seblu -** Last update Tue Aug 22 19:10:23 2006 Seblu +** Last update Fri Aug 25 15:13:58 2006 Seblu */ #include @@ -13,7 +13,7 @@ #include #include #include "parser.h" -#include "../common/mem.h" +#include "../common/macro.h" #include "../shell/shell.h" #include "../readline/readline.h" @@ -23,10 +23,28 @@ ** ============ */ -/* -** Define is parser is run for DEBBUGING -*/ -#define DEBUG_PARSER 1 + +/* 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} */ +/* }; */ + static ts_ast_node *regnode(ts_parser *parser, ts_ast_node *node); @@ -112,7 +130,6 @@ static void parse_error(ts_parser *parser, ts_token t) ts_ast_node *parse(ts_parser *parser) { - lexer_start(parser->lexer); parser->regpos = 0; parser->error = 0; // prevent of too big register ast size @@ -121,18 +138,20 @@ ts_ast_node *parse(ts_parser *parser) (parser->regsize = 50) * sizeof (ts_ast_node)); if (setjmp(parser->stack)) return NULL; + show_prompt(PROMPT_PS1); +#if DEBUG_LEXER == 1 //test lexer mode while (1) { - ts_token tok; - - tok = lexer_gettoken(parser->lexer); + ts_token tok = lexer_gettoken(parser->lexer); if (tok.id == TOK_EOF) - exit(42); + exit(69); + printf("Returned token: %d [%s]\n", tok.id, + (*tok.str == '\n') ? "\\n" : tok.str); if (tok.id == TOK_NEWLINE) - lexer_start(parser->lexer); - printf("Returned token: %d [%s]\n", tok.id, tok.str); + show_prompt(PROMPT_PS1); } +#endif return parse_input(parser); } diff --git a/src/parser/parser.h b/src/parser/parser.h index cef61bfc1e0f4be52641d02702ec6fe4699ac2d4..2485a5143566f47488536db677baff4f0168466a 100644 --- a/src/parser/parser.h +++ b/src/parser/parser.h @@ -5,7 +5,7 @@ ** Login ** ** Started on Wed Aug 2 00:49:50 2006 Seblu -** Last update Wed Aug 23 02:33:38 2006 Seblu +** Last update Fri Aug 25 15:17:29 2006 Seblu */ #include @@ -14,29 +14,34 @@ #ifndef PARSER_H_ # define PARSER_H_ -typedef enum e_token + +// Define is parser or lexer is run for DEBBUGING +#define DEBUG_PARSER 1 +#define DEBUG_LEXER 0 + +typedef enum e_tokenid { - //token free-context recognition + //token free-context recognition (lexer time) TOK_NONE, - TOK_NEWLINE, - TOK_NUMBER, - TOK_EOF, - TOK_AND, - TOK_OR, - TOK_DSEMI, - TOK_LESS, - TOK_GREAT, - TOK_DLESS, - TOK_DGREAT, - TOK_LESSAND, - TOK_GREATAND, - TOK_LESSGREAT, - TOK_DLESSDASH, - TOK_CLOBBER, - TOK_CONTEXT, - TOK_WORD, - //token context-sensitive recognition - TOK_ASSIGNMENT, + TOK_NEWLINE, // \n + TOK_EOF, // EOF + TOK_AND, // && + TOK_SEPAND, // & + TOK_OR, // || + TOK_PIPE, // | + TOK_DSEMI, // ;; + TOK_SEP, // ; + TOK_DLESSDASH, // <<- + TOK_DLESS, // << + TOK_LESSGREAT, // <> + TOK_LESSAND, // <& + TOK_LESS, // < + TOK_DGREAT, // >> + TOK_GREATAND, // >& + TOK_CLOBBER, // >| + TOK_GREAT, // > + TOK_WORD, // all others + //token context-sensitive recognition (parser time) TOK_IF, TOK_THEN, TOK_ELSE, @@ -52,30 +57,25 @@ typedef enum e_token TOK_IN, TOK_LBRACE, TOK_RBRACE, - TOK_BANG, - TOK_SEP, - TOK_SEPAND, + TOK_NUMBER, + TOK_ASSIGNMENT, + TOK_BANG } te_tokenid; typedef struct s_token { - te_tokenid id; - const char *str; + te_tokenid id; + const char *str; + size_t len; } ts_token; -typedef enum e_lexer_status - { - LEXER_READY = 1, - LEXER_END = 2, - } te_lexer_status; - typedef struct s_lexer { - te_lexer_status status; ts_token token; FILE *fs; + char eof; char *buf; - size_t buf_size; + size_t buf_size; //without \0 size_t buf_pos; } ts_lexer; @@ -90,14 +90,6 @@ typedef struct s_parser } 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 @@ -168,4 +160,11 @@ ts_token lexer_gettoken(ts_lexer *lexer); */ ts_token lexer_lookahead(ts_lexer *lexer); +/*! +** Parse input as a here-document (describe is XSI) +** +** @param lexer current lexer +*/ +void lexer_heredocument(ts_lexer *lexer); + #endif diff --git a/src/readline/readline.c b/src/readline/readline.c index f718d05ca917afc8fe76363163cd7becb453c82d..d7de272e9dca1bc83f036993f97850c302b447a1 100644 --- a/src/readline/readline.c +++ b/src/readline/readline.c @@ -5,7 +5,7 @@ ** Login ** ** Started on Wed Aug 2 01:13:56 2006 Seblu -** Last update Thu Aug 3 11:18:11 2006 Seblu +** Last update Fri Aug 25 07:52:48 2006 Seblu */ #include @@ -17,7 +17,7 @@ struct s_getln getln_stdin; char *readline(const char *prompt) { - if (isatty(STDOUT_FILENO) && isatty(STDERR_FILENO)) + if (prompt && isatty(STDOUT_FILENO) && isatty(STDERR_FILENO)) write(STDERR_FILENO, prompt, strlen(prompt)); return getln(&getln_stdin); } diff --git a/src/shell/shell.h b/src/shell/shell.h index b2b53d718ddeecc2afac10b526ccc7e42198f307..f1f77825aad8209b99d405b7390536824a3e81f5 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 Wed Aug 23 18:38:11 2006 Seblu +** Last update Fri Aug 25 07:45:07 2006 Seblu */ #ifndef SHELL_H_ @@ -13,19 +13,10 @@ # include # include +# include "../common/constant.h" # include "../alias/alias.h" # include "../option/option.h" -static const int ERROR_PARSE = 258; -static const int ERROR_FORK = 128; -static const int ERROR_REDIR = 1; - -typedef enum e_prompt_type { - TYPE_PS1 = 1, - TYPE_PS2 = 2, - TYPE_PS4 = 4 -} te_prompt_type; - typedef struct s_shell { /* struct s_var *vars; */ @@ -40,7 +31,14 @@ typedef struct s_shell ts_shell *shell_init(const char *argv0); void shell_destroy(ts_shell *sh); -const char *get_prompt(te_prompt_type pty); +const char *get_prompt(te_prompt pty); + +/*! +** Show a prompt on stderr is current shell is a plug on a tty +** +** @param pty prompt type (PS1, PS2, PS4) +*/ +void show_prompt(te_prompt pty); extern ts_shell *shell; diff --git a/src/shell/shell_entry.c b/src/shell/shell_entry.c index 460fa5bca50fb06a2f31dfbba393c4fd40004588..0ff3968e90ce9695bdf3fc86e29dfaf3d1a79d4b 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 Wed Aug 23 18:40:08 2006 Seblu +** Last update Fri Aug 25 12:24:50 2006 Seblu */ #include @@ -14,6 +14,7 @@ #include "../ast/ast.h" #include "../parser/parser.h" #include "../exec/exec.h" +#include "../common/macro.h" /* ** Global shell structure @@ -47,6 +48,8 @@ int main(int argc, char *argv[]) exec_ast(ast); ast_destruct(ast); } - while (parser->lexer->status != LEXER_END); + while (!parser->lexer->eof); + if (!isinteractive()) + fprintf(stderr, "exit\n"); return shell->status; } diff --git a/src/shell/shell_init.c b/src/shell/shell_init.c index 2b3cc3fb5cd8c6e40a016b12e604b8cd49bbc1c8..b4ee3de0a7b49776ea73e782efdd4eefd364f7e2 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 Wed Aug 23 18:41:10 2006 Seblu +** Last update Fri Aug 25 03:50:14 2006 Seblu */ #include @@ -16,7 +16,7 @@ #include #include "shell.h" #include "../option/option.h" -#include "../common/mem.h" +#include "../common/macro.h" #include "../common/common.h" diff --git a/src/shell/shell_prompt.c b/src/shell/shell_prompt.c index 1f9459febd1d487b48e89bc99b3d6166cd1dc932..01942861f9cc23492f5a93e3928bf3a383e2519a 100644 --- a/src/shell/shell_prompt.c +++ b/src/shell/shell_prompt.c @@ -5,14 +5,13 @@ ** Login ** ** Started on Sun Jul 30 02:27:59 2006 Seblu -** Last update Sat Aug 19 01:44:07 2006 Seblu +** Last update Fri Aug 25 08:18:07 2006 Seblu */ #include #include #include "shell.h" - -static char prompt[80]; +#include "../common/macro.h" /*! ** Return a prompt given by PS1, PS2, PS4 or the default if not set @@ -21,16 +20,39 @@ static char prompt[80]; ** ** @return */ -const char *get_prompt(te_prompt_type pty) +const char *get_prompt(te_prompt pty) { + static char prompt[80]; //fixme - if (pty == TYPE_PS1) { + if (pty == PROMPT_PS1) { strncpy(prompt, shell->name, 78); strcpy(prompt + strlen(shell->name), "$ "); } - else if (pty == TYPE_PS2) + else if (pty == PROMPT_PS2) strcpy(prompt, "> "); - else if (pty == TYPE_PS4) + else if (pty == PROMPT_PS4) return strcpy(prompt, ""); return prompt; } + +//todo gestion des variables ! +void show_prompt(te_prompt pty) +{ + if (!isinteractive()) + return; + char *prompt; + switch (pty) { + case PROMPT_PS1: + prompt = "42sh "; + break; + case PROMPT_PS2: + prompt = "> "; + break; + case PROMPT_PS4: + prompt = "+"; + break; + } + fflush(stderr); + fprintf(stderr, "%s", prompt); + fflush(stderr); +}