diff --git a/GRAMMAR b/GRAMMAR index dea5b1482d83d20646389c554e75342aa81b0802..ba0cea98ef591c00bafd6a8f9d2f07fc199c9d10 100644 --- a/GRAMMAR +++ b/GRAMMAR @@ -1,35 +1,19 @@ -good_input: simple_list '\n' +input: list '\n' + list EOF | '\n' | EOF -redirection: [NUMBER] '>' WORD - | [NUMBER] '<' WORD - | [NUMBER] '>>' WORD - | [NUMBER] '<<' WORD - | [NUMBER] '<<-' WORD - | [NUMBER] '>&' WORD - | [NUMBER] '<&' WORD - | [NUMBER] '>|' WORD - | [NUMBER] '<>' WORD - -element: WORD - | redirection - +list: and_or ((';'|'&') and_or)* ['&'|';'] -cmd_prefix: ASSIGMENT_WORD - | redirection +and_or: pipeline (('&&'|'||') ('\n')* pipeline)* -simple_command: (cmp_prefix)* (element)+ +pipeline: ['!'] command ('|' ('\n')* command)* command: simple_command | shell_command (redirection)* - | function_def - -simple_list: and_or ((';'|'&') and_or)* ['&'|';'] + | funcdec -and_or: pipeline (('&&'|'||') ('\n')* pipeline)* - -pipeline: ['!'] command ('|' ('\n')* command)* +simple_command: (cmp_prefix)* (element)+ shell_command: '{' compound_list '}' | '(' compound_list ')' @@ -39,10 +23,25 @@ shell_command: '{' compound_list '}' | rule_case | rule_if -rule_if: 'if' compound_list 'then' compound_list [else_clause] 'fi' +funcdec: ['function'] WORD '(' ')' ('\n')* shell_command (redirection)* -else_clause: 'else' compound_list - | 'elif' compound_list 'then' compound_list [else_clause] +redirection: [NUMBER] '>' WORD + | [NUMBER] '<' WORD + | [NUMBER] '>>' WORD + | [NUMBER] '<<' WORD + | [NUMBER] '<<-' WORD + | [NUMBER] '>&' WORD + | [NUMBER] '<&' WORD + | [NUMBER] '>|' WORD + | [NUMBER] '<>' WORD + +cmd_prefix: ASSIGMENT_WORD + | redirection + +element: WORD + | redirection + +compound_list: ('\n')* and_or ((';'|'&'|'\n') ('\n')* and_or)* [(('&'|';'|'\n') ('\n')*)] rule_for: 'for' WORD ('\n')* ['in' (WORD)+ (';'|'\n') ('\n')*] do_group @@ -50,14 +49,16 @@ rule_while: 'while' compound_list do_group rule_until: 'until' compound_list do_group -do_group: 'do' compound_list 'done' +rule_case: 'case' WORD ('\n')* 'in' ('\n')* [case_clause] 'esac' -compound_list: ('\n')* and_or ((';'|'&'|'\n') ('\n')* and_or)* [(('&'|';'|'\n') ('\n')*)] +rule_if: 'if' compound_list 'then' compound_list [else_clause] 'fi' + +else_clause: 'else' compound_list + | 'elif' compound_list 'then' compound_list [else_clause] -case: 'case' WORD ('\n')* 'in' ('\n')* [case_clause] 'esac' +do_group: 'do' compound_list 'done' case_clause: pattern (';;' (\n)* pattern)* [;;] pattern: ['('] WORD ('|' WORD)* ')' ( ('\n')* | compound_list ) -function: ['function'] WORD '(' ')' ('\n')* shell_command (redirection)* diff --git a/src/Makefile.am b/src/Makefile.am index ebfd4868381643d699be83f5978ec8fae676a275..c9f12982f88ed6b82ceb65dfaef056e0aa0d854f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -5,17 +5,23 @@ bin_PROGRAMS=42sh 42sh_SOURCES= ast/ast.h \ + ast/ast_destruct.c \ + ast/ast_sep.c \ common/common.h \ - common/macro.h \ + common/mem.h \ common/strmerge.c \ common/strvmerge.c \ - lexer/lexer.h \ + common/strndup.c \ + common/basename.c \ + exec/exec.h \ + exec/exec_ast.c \ opt/opt.h \ opt/opt.c \ opt/opt_init.c \ opt/opt_parser.c \ parser/parser.h \ parser/parser.c \ + parser/lexer.c \ readline/readline.h \ readline/readline.c \ readline/getln.c \ diff --git a/src/ast/ast.h b/src/ast/ast.h index 6ac90f3acb24a4c7ce7327ea7ace2d7893a4b421..21d6e97488155b0328edb78075e00a6b5579b0c0 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -5,7 +5,7 @@ ** Login ** ** Started on Sun Jul 30 04:40:03 2006 Seblu -** Last update Wed Aug 2 17:54:14 2006 Seblu +** Last update Thu Aug 3 03:03:42 2006 Seblu */ #ifndef AST_H_ @@ -16,13 +16,12 @@ # include # include -struct s_ast; typedef struct s_ast ts_ast_node; /* ** If ast node */ -typedef struct +typedef struct s_if_node { ts_ast_node *cond; ts_ast_node *cond_true; @@ -32,7 +31,7 @@ typedef struct /* ** For ast node */ -typedef struct +typedef struct s_for_node { char *name; ts_ast_node *values; @@ -42,7 +41,7 @@ typedef struct /* ** Case ast node */ -typedef struct +typedef struct s_case_node { char *word; //FIXME @@ -52,7 +51,7 @@ typedef struct /* ** While ast node */ -typedef struct +typedef struct s_while_node { ts_ast_node *cond; ts_ast_node *exec; @@ -61,7 +60,7 @@ typedef struct /* ** Enumerate different type of redirection */ -typedef enum +typedef enum e_redir_type { R_LESS, /* < */ R_LESSAND, /* <& */ @@ -77,7 +76,7 @@ typedef enum /* ** Redirection ast node */ -typedef struct +typedef struct s_redir_node { te_redir_type type; int fd; @@ -87,7 +86,7 @@ typedef struct /* ** Command ast node */ -typedef struct +typedef struct s_cmd_node { char **argv; ts_redir_node **redirs; @@ -100,16 +99,16 @@ typedef struct ** T_PIPE, T_SEP_* , T_AND, T_OR : binary operator ** T_BANG : unary operator but ts_bin_op with right pointer is always NULL */ -typedef struct +typedef struct s_bin_node { - ts_ast_node *left; - ts_ast_node *right; + ts_ast_node *lhs; + ts_ast_node *rhs; } ts_bin_node; /* ** Subshell ast node */ -typedef struct +typedef struct s_subshell_node { ts_ast_node *head; } ts_subshell_node; @@ -117,7 +116,7 @@ typedef struct /* ** Funcdec node */ -typedef struct +typedef struct s_funcdec_node { char *name; ts_ast_node *body; @@ -126,7 +125,7 @@ typedef struct /* ** Enumerate all node type */ -typedef enum +typedef enum e_node_type { T_IF, T_FOR, @@ -140,7 +139,7 @@ typedef enum T_BANG, T_PIPE, T_SEP_AND, - T_SEP_SEMICOMMA, + T_SEP, T_CASE, T_CASE_LIST, @@ -156,22 +155,22 @@ typedef enum /* ** This is a type for a node item */ -typedef union +typedef union u_node_item { - ts_if_node node_if; - ts_for_node node_for; - ts_case_node node_case; - ts_while_node node_while; - ts_while_node node_until; - ts_cmd_node node_cmd; - ts_bin_node node_and; - ts_bin_node node_or; - ts_subshell_node node_subshell; - ts_funcdec_node node_funcdec; - ts_bin_node node_bang; - ts_bin_node node_pipe; - ts_bin_node node_sep_semicomma; - ts_bin_node node_sep_and; + ts_if_node child_if; + ts_for_node child_for; + ts_case_node child_case; + ts_while_node child_while; + ts_while_node child_until; + ts_cmd_node child_cmd; + ts_bin_node child_and; + ts_bin_node child_or; + ts_subshell_node child_subshell; + ts_funcdec_node child_funcdec; + ts_bin_node child_bang; + ts_bin_node child_pipe; + ts_bin_node child_sep; + ts_bin_node child_sep_and; /* ts_case_item node_case_item; */ @@ -185,12 +184,14 @@ typedef union struct s_ast { te_node_type type; - tu_node_item node; + tu_node_item body; }; +void ast_destruct(ts_ast_node *ast); - +ts_ast_node *ast_create_sep(ts_ast_node *lhs, ts_ast_node *rhs); +void ast_destruct_sep(ts_ast_node *node); /* /\** */ /* ** structure wordlist ex : for var in wordlist do */ @@ -310,7 +311,7 @@ struct s_ast /* ** create shell structure */ /* *\/ */ /* struct s_42sh *ast_create_ast(struct s_42sh *shell, */ -/* struct s_ast *ast); */ +/* struct s_ast *ast; */ /* struct s_ast *ast_create_patterns(char *word, struct s_ast *case_item); */ /* struct s_ast *ast_create_case_list(struct s_ast *item, */ diff --git a/src/ast/ast_destruct.c b/src/ast/ast_destruct.c new file mode 100644 index 0000000000000000000000000000000000000000..ee55e2ec08021e21333fcefdf4da3f961d099104 --- /dev/null +++ b/src/ast/ast_destruct.c @@ -0,0 +1,18 @@ +/* +** ast_destruct.c for 42sh +** +** Made by Seblu +** Login +** +** Started on Sat Mar 25 23:11:01 2006 Seblu +** Last update Thu Aug 3 07:00:17 2006 Seblu +*/ + +#include "ast.h" + +void ast_destruct(ts_ast_node *ast) +{ + if (ast == NULL) + return; + //fixme +} diff --git a/src/ast/ast_sep.c b/src/ast/ast_sep.c new file mode 100644 index 0000000000000000000000000000000000000000..9e901785a343e1967ac5ce570cd1016b45d7193d --- /dev/null +++ b/src/ast/ast_sep.c @@ -0,0 +1,48 @@ +/* +** ast_sep.c for 42sh +** +** Made by Seblu +** Login +** +** Started on Thu Aug 3 02:41:37 2006 Seblu +** Last update Thu Aug 3 03:03:31 2006 Seblu +*/ + +#include "../common/mem.h" +#include "ast.h" + +/*! +** Create a separtor ast node +** +** @param lhs left child +** @param rhs right child +** +** @return the node +*/ +ts_ast_node *ast_create_sep(ts_ast_node *lhs, ts_ast_node *rhs) +{ + ts_ast_node *node; + + secmalloc(node, sizeof (ts_ast_node)); + node->type = T_SEP; + node->body.child_sep.lhs = lhs; + node->body.child_sep.rhs = rhs; + return node; +} + +/*! +** Destruct and separator node +** +** @param node node to destroy +*/ +void ast_destruct_sep(ts_ast_node *node) +{ + if (node->type != T_SEP) { + ast_destruct(node); + return; + } + ast_destruct(node->body.child_sep.lhs); + ast_destruct(node->body.child_sep.rhs); + free(node); +} + diff --git a/src/common/basename.c b/src/common/basename.c new file mode 100644 index 0000000000000000000000000000000000000000..0c7cd2dc5f6fce7aa15dc3ee905482ba9927209c --- /dev/null +++ b/src/common/basename.c @@ -0,0 +1,42 @@ +/* +** basename.c for 42sh +** +** Made by Seblu +** Login +** +** Started on Thu Aug 3 05:29:46 2006 Seblu +** Last update Thu Aug 3 10:36:04 2006 Seblu +*/ + +#include +#include "common.h" + +char *basename(const char *path) +{ + size_t start = 0, end = 0, len; + register size_t i; + + if ((len = strlen(path)) == 0) + return strdup(""); + //search first char without '/' from end string + for (i = len - 1; ; --i) { + if (path[i] != '/') { + end = i; + break; + } + if (i == 0) + break; + } + if (end == 0) + return strdup(""); + //search first char '/' from end string + for (i = end - 1; ; --i) { + if (path[i] == '/') { + start = i + 1; + break; + } + if (i == 0) + break; + } + return strndup(path + start, (start >= end) ? 0 : end - start); +} diff --git a/src/common/common.h b/src/common/common.h index 4cc6fb6c3f753832357ea51983133748a8f14473..4801ef98d8ff6a8f965593610a57ae64258176d1 100644 --- a/src/common/common.h +++ b/src/common/common.h @@ -5,13 +5,51 @@ ** Login ** ** Started on Sun Jul 30 03:59:48 2006 Seblu -** Last update Sun Jul 30 04:33:18 2006 Seblu +** Last update Thu Aug 3 06:01:23 2006 Seblu */ #ifndef COMMON_H_ # define COMMON_H_ +/*! +** Merge strings +** +** @param n number of string to merge +** @param s1 First string to merge +** +** @return malloced string merged +** @warning the returned string must be freed by the caller +*/ char *strmerge(int n, const char *s1, ...); + +/*! +** Merge a vector of string +** +** @param vtable strings to merge +** +** @return a string merged from @arg vtable +*/ char *strvmerge(const char * const *vtable); +/*! +** Return a malloc copy of the given, conserving only the basename +** +** @param path path where basename will be extracted +** +** @return malloced basename +** @warning Not use the standard function for reason of vicious +** definition in manuel. +*/ +char *basename(const char *path); + +/*! +** Duplicate a string for @arg n characteres +** +** @param str string to duplicate +** @param n number of caractere to duplicate +** +** @return a new malloced string +*/ +char *strndup(const char *str, size_t n); + #endif diff --git a/src/common/macro.h b/src/common/mem.h similarity index 100% rename from src/common/macro.h rename to src/common/mem.h diff --git a/src/common/strmerge.c b/src/common/strmerge.c index 01bbf247ece5747822c80aa49e8624b2ea6e00db..67bb974199f3b5af99ed3ab923394a65d483c353 100644 --- a/src/common/strmerge.c +++ b/src/common/strmerge.c @@ -5,22 +5,13 @@ ** Login ** ** Started on Tue May 16 21:23:02 2006 Seblu -** Last update Sun Jul 30 04:15:36 2006 Seblu +** Last update Thu Aug 3 05:29:21 2006 Seblu */ #include #include -#include "macro.h" +#include "mem.h" -/*! -** Merge strings -** -** @param n number of string to merge -** @param s1 First string to merge -** -** @return malloced string merged -** @warning the returned string must be freed by the caller -*/ char *strmerge(int n, const char *s1, ...) { va_list param; diff --git a/src/common/strndup.c b/src/common/strndup.c new file mode 100644 index 0000000000000000000000000000000000000000..b5faf8a50d37b715aba77743abb4eb07942d4b17 --- /dev/null +++ b/src/common/strndup.c @@ -0,0 +1,30 @@ +/* +** strndup.c for 42sh +** +** Made by Seblu +** Login +** +** Started on Thu Aug 3 05:56:28 2006 Seblu +** Last update Thu Aug 3 05:58:42 2006 Seblu +*/ + +#include +#include + +char *strndup(const char *str, size_t n) +{ + size_t length; + size_t max_length; + size_t i; + char *new; + + max_length = n; + if ((length = strlen(str)) > max_length) + length = max_length; + if ((new = malloc((length + 1) * sizeof (char))) == NULL) + return NULL; + for (i = 0; i < length; ++i) + new[i] = str[i]; + new[length] = 0; + return new; +} diff --git a/src/common/strvmerge.c b/src/common/strvmerge.c index b38f60d32b6823a7ca38991afba7c769c8541c18..c1043deafe41e28a5c58421103cb2155313a3833 100644 --- a/src/common/strvmerge.c +++ b/src/common/strvmerge.c @@ -5,19 +5,12 @@ ** Login ** ** Started on Sun Jul 30 04:03:35 2006 Seblu -** Last update Sun Jul 30 04:36:05 2006 Seblu +** Last update Thu Aug 3 05:29:38 2006 Seblu */ #include -#include "macro.h" +#include "mem.h" -/*! -** Merge a vector of string -** -** @param vtable strings to merge -** -** @return a string merged from @arg vtable -*/ char *strvmerge(const char *const *vtable) { size_t string_sz = 0; diff --git a/src/exec/exec.h b/src/exec/exec.h new file mode 100644 index 0000000000000000000000000000000000000000..f03d69dafb3a4174562a8ad14650fcbd97fbf42a --- /dev/null +++ b/src/exec/exec.h @@ -0,0 +1,41 @@ +/* +** execution.h for 42sh +** +** Made by Seblu +** Login +** +** Started on Sun Mar 30 16:02:07 2006 Seblu +** Last update Thu Aug 3 01:20:18 2006 Seblu +*/ + +#ifndef EXEC_H_ +# define EXEC_H_ + +# include +# include +# include "../ast/ast.h" + +void exec_ast(ts_ast_node *node); + +/* void exec_node(struct s_ast *node, struct s_42sh *sh); */ +/* void exec_list(struct s_list *node, struct s_42sh *sh); */ +/* void exec_if(struct s_if *node, struct s_42sh *sh); */ +/* void exec_while(struct s_while *node, struct s_42sh *sh); */ +/* void exec_until(struct s_while *node, struct s_42sh *sh); */ +/* void exec_and(struct s_op *node, struct s_42sh *sh); */ +/* void exec_or(struct s_op *node, struct s_42sh *sh); */ +/* void exec_cmd(struct s_cmd *node, struct s_42sh *sh); */ +/* void exec_pipe(struct s_op *node, struct s_42sh *sh); */ +/* void exec_bang(struct s_op *node, struct s_42sh *sh); */ +/* void exec_sepand(struct s_op *node, struct s_42sh *sh); */ +/* void exec_sepsemicolon(struct s_op *node, struct s_42sh *sh); */ +/* void exec_line(struct s_op *node, struct s_42sh *sh); */ +/* void exec_subshell(struct s_subshell *node, struct s_42sh *sh); */ + +/* /\* FIXME *\/ */ + +/* void exec_for(struct s_for *node, struct s_42sh *sh); */ +/* void exec_case(struct s_case *node, struct s_42sh *sh); */ +/* void exec_funcdec(struct s_funcdec *node, struct s_42sh *sh); */ + +#endif diff --git a/src/exec/exec_ast.c b/src/exec/exec_ast.c new file mode 100644 index 0000000000000000000000000000000000000000..6ea4db646a2126719ff50d5e725b1777c70eaad9 --- /dev/null +++ b/src/exec/exec_ast.c @@ -0,0 +1,55 @@ +/* +** exec_node.c for 42sh +** +** Made by Seblu +** Login +** +** Started on Sat Mar 25 14:51:09 2006 Seblu +** Last update Sat Apr 15 09:12:38 2006 Seblu +*/ + +#include "exec.h" + +/*! +** Execute a node of ast by calling the good function +** +** @param node node to execute +** @param sh shell struct +*/ +void exec_ast(ts_ast_node *node) +{ + node = node; +} + +/* { */ +/* if (node == NULL) */ +/* return; */ +/* else if (node->type == T_CMD) */ +/* exec_cmd(&node->data.node_cmd, sh); */ +/* else if (node->type == T_PIPE) */ +/* exec_pipe(&node->data.node_op, sh); */ +/* else if (node->type == T_LINE) */ +/* exec_line(&node->data.node_op, sh); */ +/* else if (node->type == T_SEP_AND) */ +/* exec_sepand(&node->data.node_op, sh); */ +/* else if (node->type == T_SEP_SEMICOMMA) */ +/* exec_sepsemicolon(&node->data.node_op, sh); */ +/* else if (node->type == T_IF) */ +/* exec_if(&node->data.node_if, sh); */ +/* else if (node->type == T_FOR) */ +/* exec_for(&node->data.node_for, sh); */ +/* else if (node->type == T_AND) */ +/* exec_and(&node->data.node_op, sh); */ +/* else if (node->type == T_OR) */ +/* exec_or(&node->data.node_op, sh); */ +/* else if (node->type == T_WHILE) */ +/* exec_while(&node->data.node_while, sh); */ +/* else if (node->type == T_UNTIL) */ +/* exec_until(&node->data.node_while, sh); */ +/* else if (node->type == T_BANG) */ +/* exec_bang(&node->data.node_op, sh); */ +/* else if (node->type == T_SUBSHELL) */ +/* exec_subshell(&node->data.node_subshell, sh); */ +/* else */ +/* assert(0); */ +/* } */ diff --git a/src/exec/exec_node.c b/src/exec/exec_node.c index 2bdfac0ee8f7305376cba4f2a344031c4ce76d1c..6ea4db646a2126719ff50d5e725b1777c70eaad9 100644 --- a/src/exec/exec_node.c +++ b/src/exec/exec_node.c @@ -1,5 +1,5 @@ /* -** exec_node.c for 42sh in /home/seblu +** exec_node.c for 42sh ** ** Made by Seblu ** Login @@ -8,9 +8,7 @@ ** Last update Sat Apr 15 09:12:38 2006 Seblu */ -#include "execution.h" - -#include "mem.h" +#include "exec.h" /*! ** Execute a node of ast by calling the good function @@ -18,37 +16,40 @@ ** @param node node to execute ** @param sh shell struct */ -void exec_node(struct s_ast *node, struct s_42sh *sh) +void exec_ast(ts_ast_node *node) { - assert(sh); - if (node == NULL) - return; - else if (node->type == T_CMD) - exec_cmd(&node->data.node_cmd, sh); - else if (node->type == T_PIPE) - exec_pipe(&node->data.node_op, sh); - else if (node->type == T_LINE) - exec_line(&node->data.node_op, sh); - else if (node->type == T_SEP_AND) - exec_sepand(&node->data.node_op, sh); - else if (node->type == T_SEP_SEMICOMMA) - exec_sepsemicolon(&node->data.node_op, sh); - else if (node->type == T_IF) - exec_if(&node->data.node_if, sh); - else if (node->type == T_FOR) - exec_for(&node->data.node_for, sh); - else if (node->type == T_AND) - exec_and(&node->data.node_op, sh); - else if (node->type == T_OR) - exec_or(&node->data.node_op, sh); - else if (node->type == T_WHILE) - exec_while(&node->data.node_while, sh); - else if (node->type == T_UNTIL) - exec_until(&node->data.node_while, sh); - else if (node->type == T_BANG) - exec_bang(&node->data.node_op, sh); - else if (node->type == T_SUBSHELL) - exec_subshell(&node->data.node_subshell, sh); - else - assert(0); + node = node; } + +/* { */ +/* if (node == NULL) */ +/* return; */ +/* else if (node->type == T_CMD) */ +/* exec_cmd(&node->data.node_cmd, sh); */ +/* else if (node->type == T_PIPE) */ +/* exec_pipe(&node->data.node_op, sh); */ +/* else if (node->type == T_LINE) */ +/* exec_line(&node->data.node_op, sh); */ +/* else if (node->type == T_SEP_AND) */ +/* exec_sepand(&node->data.node_op, sh); */ +/* else if (node->type == T_SEP_SEMICOMMA) */ +/* exec_sepsemicolon(&node->data.node_op, sh); */ +/* else if (node->type == T_IF) */ +/* exec_if(&node->data.node_if, sh); */ +/* else if (node->type == T_FOR) */ +/* exec_for(&node->data.node_for, sh); */ +/* else if (node->type == T_AND) */ +/* exec_and(&node->data.node_op, sh); */ +/* else if (node->type == T_OR) */ +/* exec_or(&node->data.node_op, sh); */ +/* else if (node->type == T_WHILE) */ +/* exec_while(&node->data.node_while, sh); */ +/* else if (node->type == T_UNTIL) */ +/* exec_until(&node->data.node_while, sh); */ +/* else if (node->type == T_BANG) */ +/* exec_bang(&node->data.node_op, sh); */ +/* else if (node->type == T_SUBSHELL) */ +/* exec_subshell(&node->data.node_subshell, sh); */ +/* else */ +/* assert(0); */ +/* } */ diff --git a/src/lexer/lexer.h b/src/lexer/lexer.h deleted file mode 100644 index 12c8d4e4a829c6a4823acd7d5eb096199fa8f860..0000000000000000000000000000000000000000 --- a/src/lexer/lexer.h +++ /dev/null @@ -1,15 +0,0 @@ -/* -** lexer.h for 42sh -** -** Made by Seblu -** Login -** -** Started on Sun Jul 30 04:36:53 2006 Seblu -** Last update Sun Jul 30 04:37:57 2006 Seblu -*/ - -#ifndef LEXER_H_ -# define LEXER_H_ - - -#endif diff --git a/src/opt/opt_init.c b/src/opt/opt_init.c index 8d585494ac89527adee6d338566bbb2ecdf57ae4..02bf7761386e6abe35db15198b8f65edaeccb0f3 100644 --- a/src/opt/opt_init.c +++ b/src/opt/opt_init.c @@ -5,11 +5,11 @@ ** Login ** ** Started on Sun Jul 30 03:33:09 2006 Seblu -** Last update Sun Jul 30 03:57:27 2006 Seblu +** Last update Thu Aug 3 02:45:51 2006 Seblu */ #include "opt.h" -#include "../common/macro.h" +#include "../common/mem.h" /*! ** Create a new option structure diff --git a/src/opt/opt_parser.c b/src/opt/opt_parser.c index 90f3158e0cb6f3344c35f11c709d82e2f43aa261..f590b1499377a15f036a3dfa8031e83b504ceae0 100644 --- a/src/opt/opt_parser.c +++ b/src/opt/opt_parser.c @@ -5,7 +5,7 @@ ** Login ** ** Started on Sun Jul 30 03:28:26 2006 Seblu -** Last update Sun Jul 30 04:37:35 2006 Seblu +** Last update Thu Aug 3 05:22:32 2006 Seblu */ #include diff --git a/src/parser/lexer.c b/src/parser/lexer.c new file mode 100644 index 0000000000000000000000000000000000000000..afd5cb44e2c92205b957fcf111c43531c37b9b81 --- /dev/null +++ b/src/parser/lexer.c @@ -0,0 +1,120 @@ +/* +** lexer.c for 42sh +** +** Made by Seblu +** Login +** +** Started on Sun Jul 30 04:36:53 2006 Seblu +** Last update Thu Aug 3 12:39:34 2006 Seblu +*/ + +#include +#include +#include "parser.h" +#include "../shell/shell.h" +#include "../readline/readline.h" + +int lexer_reconize(ts_parser *parser); + +ts_token tokens[] = + { + {TOK_AND, "&&"}, + {TOK_OR, "||"}, + {TOK_DSEMI, ";;"}, + {TOK_DLESS, "<<"}, + {TOK_DGREAT, ">>"}, + {TOK_LESSAND, "<&"}, + {TOK_GREATAND, ">&"}, + {TOK_LESSGREAT, "<>"}, + {TOK_DLESSDASH, "<<-"}, + {TOK_CLOBBER, ">|"}, + {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_SEP, ";"}, + {TOK_SEPAND, "&"}, + {TOK_NEWLINE, "\n"}, + {0,0} + }; + +void lexer_reset(ts_parser *parser) +{ + parser->current.id = TOK_NONE; + parser->current.str = "none"; + if (parser->buf != NULL) + free(parser->buf); + parser->buf = NULL; + parser->buf_size = 0; + parser->buf_pos = 0; +} + +const char *get_token_string(t_token t) +{ + for (register int i = 0; tokens[i].str; ++i) + if (tokens[i].id == t) + return tokens[i].str; + return "unknow"; +} + +ts_token lexer_get(ts_parser *parser) +{ + if (parser->current.id == TOK_NONE) + lexer_eat(parser); + return parser->current; +} + +void lexer_eat(ts_parser *parser) +{ + if (parser->status == PARSE_END) + return; + if (parser->buf_size == 0) { + if ((parser->buf = readline(get_prompt(TYPE_PS1))) == NULL) { + parser->current.id = TOK_EOF; + parser->status = PARSE_END; + return; + } + parser->buf_pos = 0; + parser->buf_size = strlen(parser->buf); + } + if (parser->buf_size > 0 && + parser->buf_size != parser->buf_pos) { + if (lexer_reconize(parser)) + return; + } + do + if ((parser->buf = readline(get_prompt(TYPE_PS2))) == NULL) { + parser->current.id = TOK_EOF; + parser->status = PARSE_END; + } + while (lexer_reconize(parser)); +} + +int lexer_reconize(ts_parser *parser) +{ + size_t n; + + for (register int i = 0; tokens[i].str; ++i) + if (!strncmp(tokens[i].str, parser->buf + parser->buf_pos, + n = strlen(tokens[i].str))) { + parser->current = tokens[i]; + parser->buf_pos += n; + printf("reconized %d\n", tokens[i].id); + return 1; + } + parser->current.id = TOK_NONE; + parser->current.str = "none"; + return 0; +} diff --git a/src/parser/parser.c b/src/parser/parser.c index 536e00c005df12bead59e40f97f363bacbfeebce..2f2a74e6c409bebeb01081da7b5691f7a74bdd56 100644 --- a/src/parser/parser.c +++ b/src/parser/parser.c @@ -1,26 +1,214 @@ /* -** parser.c for 42sh in /home/seblu/svn/42sh/src/parser +** parser.c for 42sh ** ** Made by Seblu ** Login ** ** Started on Wed Aug 2 00:56:07 2006 Seblu -** Last update Wed Aug 2 17:47:01 2006 Seblu +** Last update Thu Aug 3 12:30:15 2006 Seblu */ +#include +#include +#include #include "parser.h" +#include "../common/mem.h" +#include "../shell/shell.h" +#include "../readline/readline.h" + +/* +** Declaration +*/ /*! -** Parse a File stream, and return the ast +** Parse a line ** -** @param fs file stream to parse +** @param parser ** -** @return ast from the file stream +** @return +*/ +static ts_ast_node *parse_input(ts_parser *parser); + + +static ts_ast_node *parse_list(ts_parser *parser); + +static ts_ast_node *parse_andor(ts_parser *parser); + +/* +** Implemantation */ -ts_ast_node *parse(FILE* fs) + +ts_parser *parser_init(FILE *fs) +{ + ts_parser *new; + + secmalloc(new, sizeof (ts_parser)); + fflush(fs); + new->fs = fs; + lexer_reset(new); + return new; +} + +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; + shell->status = ERROR_PARSE; +} + +ts_ast_node *parse(ts_parser *parser) +{ + lexer_reset(parser); + parser->status = PARSE_OK; + return parse_input(parser); +} + +static ts_ast_node *parse_input(ts_parser *parser) +{ + ts_token cur_token; + ts_ast_node *buf; + + lexer_eat(parser); + cur_token = lexer_get(parser); + if (cur_token.id == TOK_EOF) { + parser->status = PARSE_END; + return NULL; + } + if (cur_token.id == TOK_NEWLINE) + return ast_create_sep(NULL, NULL); + buf = parse_list(parser); + cur_token = lexer_get(parser); + if (cur_token.id != TOK_EOF || cur_token.id != TOK_NEWLINE) + parse_error(parser, cur_token); + return buf; +} + +static ts_ast_node *parse_list(ts_parser *parser) { - int fd; + ts_token next_token; + ts_ast_node *buf; + + parse_andor(parser); + lexer_eat(parser); + next_token = lexer_get(parser); + if (next_token.id != TOK_SEP && next_token.id != TOK_SEPAND) { + parse_error(parser, next_token); + return buf; + } + return NULL; +} - fd = fileno(fs); +static ts_ast_node *parse_andor(ts_parser *parser) +{ + parser=parser; return NULL; } + +/* static ts_ast_node *parse_pipeline(ts_parser *parser) */ +/* { */ +/* parser=parser; */ +/* return NULL; */ +/* } */ + +/* static ts_ast_node *parse_command(ts_parser *parser) */ +/* { */ +/* parser=parser; */ +/* return NULL; */ +/* } */ + +/* static ts_ast_node *parse_simplecommand(ts_parser *parser) */ +/* { */ +/* parser=parser; */ +/* return NULL; */ +/* } */ + +/* static ts_ast_node *parse_shellcommand(ts_parser *parser) */ +/* { */ +/* parser=parser; */ +/* return NULL; */ +/* } */ + +/* static ts_ast_node *parse_funcdec(ts_parser *parser) */ +/* { */ +/* parser=parser; */ +/* return NULL; */ +/* } */ + +/* static ts_ast_node *parse_cmdprefix(ts_parser *parser) */ +/* { */ +/* parser=parser; */ +/* return NULL; */ +/* } */ + +/* static ts_ast_node *parse_redirection(ts_parser *parser) */ +/* { */ +/* parser=parser; */ +/* return NULL; */ +/* } */ + +/* static ts_ast_node *parse_element(ts_parser *parser) */ +/* { */ +/* parser=parser; */ +/* return NULL; */ +/* } */ + +/* static ts_ast_node *parse_compound_list(ts_parser *parser) */ +/* { */ +/* parser=parser; */ +/* return NULL; */ +/* } */ + +/* static ts_ast_node *parse_rulefor(ts_parser *parser) */ +/* { */ +/* parser=parser; */ +/* return NULL; */ +/* } */ + +/* static ts_ast_node *parse_rulewhile(ts_parser *parser) */ +/* { */ +/* parser=parser; */ +/* return NULL; */ +/* } */ + +/* static ts_ast_node *parse_ruleuntil(ts_parser *parser) */ +/* { */ +/* parser=parser; */ +/* return NULL; */ +/* } */ + +/* static ts_ast_node *parse_rulecase(ts_parser *parser) */ +/* { */ +/* parser=parser; */ +/* return NULL; */ +/* } */ + +/* static ts_ast_node *parse_ruleif(ts_parser *parser) */ +/* { */ +/* parser=parser; */ +/* return NULL; */ +/* } */ + +/* static ts_ast_node *parse_elseclause(ts_parser *parser) */ +/* { */ +/* parser=parser; */ +/* return NULL; */ +/* } */ + +/* static ts_ast_node *parse_dogroup(ts_parser *parser) */ +/* { */ +/* parser=parser; */ +/* return NULL; */ +/* } */ + +/* static ts_ast_node *parse_caseclause(ts_parser *parser) */ +/* { */ +/* parser=parser; */ +/* return NULL; */ +/* } */ + +/* static ts_ast_node *parse_pattern(ts_parser *parser) */ +/* { */ +/* parser=parser; */ +/* return NULL; */ +/* } */ diff --git a/src/parser/parser.h b/src/parser/parser.h index d4ad9a6541a95c212f3d44531368df47d952da80..0db08c0d2939105783bd0f1b0edb758930a65135 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 2 17:47:18 2006 Seblu +** Last update Thu Aug 3 12:28:14 2006 Seblu */ #include @@ -14,6 +14,117 @@ #ifndef PARSER_H_ # define PARSER_H_ -ts_ast_node *parse(FILE* fs); +# define TOK_AND 1 +# define TOK_OR 2 +# define TOK_DSEMI 3 +# define TOK_DLESS 4 +# define TOK_DGREAT 5 +# define TOK_LESSAND 6 +# define TOK_GREATAND 7 +# define TOK_LESSGREAT 8 +# define TOK_DLESSDASH 9 +# define TOK_CLOBBER 10 +# define TOK_IF 11 +# define TOK_THEN 12 +# define TOK_ELSE 13 +# define TOK_FI 14 +# define TOK_ELIF 15 +# define TOK_DO 16 +# define TOK_DONE 17 +# define TOK_CASE 18 +# define TOK_ESAC 19 +# define TOK_WHILE 20 +# define TOK_UNTIL 21 +# define TOK_FOR 22 +# define TOK_IN 23 +# define TOK_LBRACE 24 +# define TOK_RBRACE 25 +# define TOK_BANG 26 +# define TOK_NEWLINE 27 +# define TOK_SEP 28 +# define TOK_SEPAND 29 +# define TOK_EOF 30 +# define TOK_NONE 31 + +typedef int t_token; + +typedef struct s_token +{ + t_token id; + const char *str; +} ts_token; + + +typedef enum e_parse_status + { + PARSE_OK, + PARSE_ERROR, + PARSE_END + } te_parse_status; + +typedef struct s_parser +{ + te_parse_status status; + ts_token current; + FILE *fs; + char *buf; + size_t buf_size; + size_t buf_pos; +} ts_parser; + +/*! +** Parser initialization +** +** @param fs file stream to read +** +** @return the new struct +*/ +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 +** +** @param parser the parser where we do this parse +** +** @return ast_to_execute +*/ +ts_ast_node *parse(ts_parser *parser); + +/*! +** Set (or reset) the lexer +** +** @param parser lexer to reset +*/ +void lexer_reset(ts_parser *parser); + +/*! +** Return the current token +** +** @return the current token +*/ +ts_token lexer_get(ts_parser *lex); + +/*! +** Eat a token (miam miam) +*/ +void lexer_eat(ts_parser *lex); + +/*! +** Return a token string. Transform a t_token into string +** +** @param t token id to transform +** +** @return token string representation +*/ +const char *get_token_string(t_token t); #endif diff --git a/src/readline/getln.c b/src/readline/getln.c index 7d7b55cdde45c57c873efe23afdee5673c4327d6..4d0e1ab5e73550f3a7a86c91ddf100ebfd0a3a7f 100644 --- a/src/readline/getln.c +++ b/src/readline/getln.c @@ -5,9 +5,12 @@ ** Login ** ** Started on Wed Aug 2 01:25:01 2006 Seblu -** Last update Wed Aug 2 01:38:22 2006 Seblu +** Last update Thu Aug 3 11:44:30 2006 Seblu */ +#include +#include +#include #include "readline.h" /*! @@ -17,7 +20,7 @@ ** ** @return lenght of the string */ -inline static size_t sstrlen(const char *s) +static size_t sstrlen(const char *s) { if (s == NULL) return 0; @@ -27,13 +30,13 @@ inline static size_t sstrlen(const char *s) /* ** Append a string to the buffer string */ -inline static void buf_str(char **str, char *append, unsigned n) +static void buf_str(char **str, char *append, unsigned n) { unsigned ln; unsigned i; unsigned j; - ln = len(*str); + ln = sstrlen(*str); if ((*str = realloc(*str, (ln + n + 1) * sizeof (char))) == NULL) exit(1); for (i = ln, j = 0; i < ln + n; i++, j++) @@ -82,13 +85,13 @@ char *getln(struct s_getln *buf) { if (buf->data[i] == '\n') { - buf_str(&(string), buf->data + buf->offset, i - buf->offset); + buf_str(&string, buf->data + buf->offset, i - buf->offset + 1); buf->offset = i + 1; return string; } } if (buf->size - buf->offset > 0) - buf_str(&(string), buf->data + buf->offset, buf->size - buf->offset); + buf_str(&string, buf->data + buf->offset, buf->size - buf->offset); buf->offset = 0; buf->size = read(buf->fd, buf->data, GETLN_BUF_SIZE); if (buf->size < 0) diff --git a/src/readline/readline.c b/src/readline/readline.c index b08319e1c6a3e1d5db09e66841e34285b0d82893..f718d05ca917afc8fe76363163cd7becb453c82d 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 Wed Aug 2 20:24:51 2006 Seblu +** Last update Thu Aug 3 11:18:11 2006 Seblu */ #include diff --git a/src/shell/shell.h b/src/shell/shell.h index 2e8bda0832f4154f1ee197a35b6da360271f5a85..821a2440110de9b9b0451504c7bb6ffacc578382 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 Sun Jul 30 03:42:43 2006 Seblu +** Last update Thu Aug 3 07:01:26 2006 Seblu */ #ifndef SHELL_H_ @@ -15,25 +15,31 @@ # include # include "../opt/opt.h" -static const int SCAN_ERROR = 1; -static const int PARSE_ERROR = 2; -static const int FORK_ERROR = 128; -static const int RED_ERROR = 1; +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 +typedef struct s_shell { -/* struct s_ast *ast; */ /* struct s_var *vars; */ /* struct s_func *funcs; */ /* struct s_history *history; */ ts_opt *opt; - int last_status; + char *name; + int status; } ts_shell; -ts_shell *shell_init(void); +ts_shell *shell_init(const char *argv0); void shell_destroy(ts_shell *sh); -ts_shell *shell; +const char *get_prompt(te_prompt_type pty); + +ts_shell *shell; #endif /* !SHELL_H_ */ diff --git a/src/shell/shell_entry.c b/src/shell/shell_entry.c index 0aadd7f179df8344ac04cfccccad59361553fb73..991ff775f43593f1cbcf8ded3f72218fb732c982 100644 --- a/src/shell/shell_entry.c +++ b/src/shell/shell_entry.c @@ -1,15 +1,19 @@ /* -** main.c for 42sh in /home/seblu/devel/c/42sh/src/execution +** main.c for 42sh ** ** Made by Seblu ** Login ** ** Started on Mon Apr 10 23:57:28 2006 Seblu -** Last update Sun Jul 30 03:15:49 2006 Seblu +** Last update Thu Aug 3 07:01:52 2006 Seblu */ #include +#include #include "shell.h" +#include "../ast/ast.h" +#include "../parser/parser.h" +#include "../exec/exec.h" /* ** Global shell structure @@ -26,16 +30,23 @@ ts_shell *shell = NULL; */ int main(int argc, char *argv[]) { - int ret; + ts_ast_node *ast; + ts_parser *parser; - /* shell initialization */ - shell = shell_init(); - /* parse arg line */ + // shell initialization + shell = shell_init(argv[0]); + // parse argv opt_parser(argc, argv, shell->opt); - //open_parse(argc, argv, shell); - /* if (shell->ast) */ - /* exec_start(shell); */ - ret = shell->last_status; - shell_destroy(shell); - return ret; + // shell parser init + parser = parser_init(stdin); + // parse and execute stdin stream + do + { + ast = parse(parser); + if (parser->status == PARSE_OK) + exec_ast(ast); + ast_destruct(ast); + } + while (parser->status != PARSE_END); + return shell->status; } diff --git a/src/shell/shell_init.c b/src/shell/shell_init.c index 76517b625ab469fc6efa28007e35351b7c3feaae..e30c241359e376ae7c29b028eab09faea312170a 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 Sun Jul 30 03:39:46 2006 Seblu +** Last update Thu Aug 3 05:28:33 2006 Seblu */ #include @@ -16,7 +16,8 @@ #include #include "shell.h" #include "../opt/opt.h" -#include "../common/macro.h" +#include "../common/mem.h" +#include "../common/common.h" /* static int pwd_isgood(); */ @@ -27,14 +28,12 @@ ** ** @return the new shell structure */ -ts_shell *shell_init(void) +ts_shell *shell_init(const char *argv0) { - ts_shell *new; -/* char *tmp; */ + ts_shell *new; secmalloc(new, sizeof (ts_shell)); -/* new->ast = NULL; */ -/* new->vars = var_create(); */ +/* new->vars = NULL; */ /* new->funcs = NULL; */ /* new->history = NULL; */ new->opt = opt_init(); @@ -44,7 +43,8 @@ ts_shell *shell_init(void) /* free(tmp); */ /* } */ /* var_unsetenv("OLDPWD"); */ - new->last_status = 0; + new->name = basename(argv0); + new->status = 0; return new; } diff --git a/src/shell/shell_prompt.c b/src/shell/shell_prompt.c index 6c2563c379a2341417a6585e8ef731526462e785..45a603307e1d7f4b4e57fe4b62a4d551510db276 100644 --- a/src/shell/shell_prompt.c +++ b/src/shell/shell_prompt.c @@ -5,13 +5,32 @@ ** Login ** ** Started on Sun Jul 30 02:27:59 2006 Seblu -** Last update Sun Jul 30 03:17:23 2006 Seblu +** Last update Thu Aug 3 11:10:46 2006 Seblu */ #include +#include +#include "shell.h" -void shell_prompt(void) +static char prompt[80]; + +/*! +** Return a prompt given by PS1, PS2, PS4 or the default if not set +** +** @param type +** +** @return +*/ +const char *get_prompt(te_prompt_type pty) { - printf("42sh$"); - fflush(stdout); + //fixme + if (pty == TYPE_PS1) { + strncpy(prompt, shell->name, 78); + strcpy(prompt + strlen(shell->name), "$ "); + } + else if (pty == TYPE_PS2) + strcpy(prompt, "> "); + else if (pty == TYPE_PS4) + return strcpy(prompt, ""); + return prompt; }