📄 parse.y
字号:
{ COMMAND *tc; tc = $3; if (tc->redirects) { register REDIRECT *t; for (t = tc->redirects; t->next; t = t->next) ; t->next = $4; } else tc->redirects = $4; $$ = make_coproc_command ($2->word, $3); $$->flags |= CMD_WANT_SUBSHELL|CMD_COPROC_SUBSHELL; } | COPROC simple_command { $$ = make_coproc_command ("COPROC", clean_simple_command ($2)); $$->flags |= CMD_WANT_SUBSHELL|CMD_COPROC_SUBSHELL; } ;if_command: IF compound_list THEN compound_list FI { $$ = make_if_command ($2, $4, (COMMAND *)NULL); } | IF compound_list THEN compound_list ELSE compound_list FI { $$ = make_if_command ($2, $4, $6); } | IF compound_list THEN compound_list elif_clause FI { $$ = make_if_command ($2, $4, $5); } ;group_command: '{' compound_list '}' { $$ = make_group_command ($2); } ;arith_command: ARITH_CMD { $$ = make_arith_command ($1); } ;cond_command: COND_START COND_CMD COND_END { $$ = $2; } ; elif_clause: ELIF compound_list THEN compound_list { $$ = make_if_command ($2, $4, (COMMAND *)NULL); } | ELIF compound_list THEN compound_list ELSE compound_list { $$ = make_if_command ($2, $4, $6); } | ELIF compound_list THEN compound_list elif_clause { $$ = make_if_command ($2, $4, $5); } ;case_clause: pattern_list | case_clause_sequence pattern_list { $2->next = $1; $$ = $2; } ;pattern_list: newline_list pattern ')' compound_list { $$ = make_pattern_list ($2, $4); } | newline_list pattern ')' newline_list { $$ = make_pattern_list ($2, (COMMAND *)NULL); } | newline_list '(' pattern ')' compound_list { $$ = make_pattern_list ($3, $5); } | newline_list '(' pattern ')' newline_list { $$ = make_pattern_list ($3, (COMMAND *)NULL); } ;case_clause_sequence: pattern_list SEMI_SEMI { $$ = $1; } | case_clause_sequence pattern_list SEMI_SEMI { $2->next = $1; $$ = $2; } | pattern_list SEMI_AND { $1->flags |= CASEPAT_FALLTHROUGH; $$ = $1; } | case_clause_sequence pattern_list SEMI_AND { $2->flags |= CASEPAT_FALLTHROUGH; $2->next = $1; $$ = $2; } | pattern_list SEMI_SEMI_AND { $1->flags |= CASEPAT_TESTNEXT; $$ = $1; } | case_clause_sequence pattern_list SEMI_SEMI_AND { $2->flags |= CASEPAT_TESTNEXT; $2->next = $1; $$ = $2; } ;pattern: WORD { $$ = make_word_list ($1, (WORD_LIST *)NULL); } | pattern '|' WORD { $$ = make_word_list ($3, $1); } ;/* A list allows leading or trailing newlines and newlines as operators (equivalent to semicolons). It must end with a newline or semicolon. Lists are used within commands such as if, for, while. */list: newline_list list0 { $$ = $2; if (need_here_doc) gather_here_documents (); } ;compound_list: list | newline_list list1 { $$ = $2; } ;list0: list1 '\n' newline_list | list1 '&' newline_list { if ($1->type == cm_connection) $$ = connect_async_list ($1, (COMMAND *)NULL, '&'); else $$ = command_connect ($1, (COMMAND *)NULL, '&'); } | list1 ';' newline_list ;list1: list1 AND_AND newline_list list1 { $$ = command_connect ($1, $4, AND_AND); } | list1 OR_OR newline_list list1 { $$ = command_connect ($1, $4, OR_OR); } | list1 '&' newline_list list1 { if ($1->type == cm_connection) $$ = connect_async_list ($1, $4, '&'); else $$ = command_connect ($1, $4, '&'); } | list1 ';' newline_list list1 { $$ = command_connect ($1, $4, ';'); } | list1 '\n' newline_list list1 { $$ = command_connect ($1, $4, ';'); } | pipeline_command { $$ = $1; } ;simple_list_terminator: '\n' | yacc_EOF ;list_terminator:'\n' { $$ = '\n'; } | ';' { $$ = ';'; } | yacc_EOF { $$ = yacc_EOF; } ;newline_list: | newline_list '\n' ;/* A simple_list is a list that contains no significant newlines and no leading or trailing newlines. Newlines are allowed only following operators, where they are not significant. This is what an inputunit consists of. */simple_list: simple_list1 { $$ = $1; if (need_here_doc) gather_here_documents (); if ((parser_state & PST_CMDSUBST) && current_token == shell_eof_token) { global_command = $1; eof_encountered = 0; rewind_input_string (); YYACCEPT; } } | simple_list1 '&' { if ($1->type == cm_connection) $$ = connect_async_list ($1, (COMMAND *)NULL, '&'); else $$ = command_connect ($1, (COMMAND *)NULL, '&'); if (need_here_doc) gather_here_documents (); if ((parser_state & PST_CMDSUBST) && current_token == shell_eof_token) { global_command = $1; eof_encountered = 0; rewind_input_string (); YYACCEPT; } } | simple_list1 ';' { $$ = $1; if (need_here_doc) gather_here_documents (); if ((parser_state & PST_CMDSUBST) && current_token == shell_eof_token) { global_command = $1; eof_encountered = 0; rewind_input_string (); YYACCEPT; } } ;simple_list1: simple_list1 AND_AND newline_list simple_list1 { $$ = command_connect ($1, $4, AND_AND); } | simple_list1 OR_OR newline_list simple_list1 { $$ = command_connect ($1, $4, OR_OR); } | simple_list1 '&' simple_list1 { if ($1->type == cm_connection) $$ = connect_async_list ($1, $3, '&'); else $$ = command_connect ($1, $3, '&'); } | simple_list1 ';' simple_list1 { $$ = command_connect ($1, $3, ';'); } | pipeline_command { $$ = $1; } ;pipeline_command: pipeline { $$ = $1; } | BANG pipeline_command { if ($2) $2->flags ^= CMD_INVERT_RETURN; /* toggle */ $$ = $2; } | timespec pipeline_command { if ($2) $2->flags |= $1; $$ = $2; } | timespec list_terminator { ELEMENT x; /* Boy, this is unclean. `time' by itself can time a null command. We cheat and push a newline back if the list_terminator was a newline to avoid the double-newline problem (one to terminate this, one to terminate the command) */ x.word = 0; x.redirect = 0; $$ = make_simple_command (x, (COMMAND *)NULL); $$->flags |= $1; /* XXX - let's cheat and push a newline back */ if ($2 == '\n') token_to_read = '\n'; } | BANG list_terminator { ELEMENT x; /* This is just as unclean. Posix says that `!' by itself should be equivalent to `false'. We cheat and push a newline back if the list_terminator was a newline to avoid the double-newline problem (one to terminate this, one to terminate the command) */ x.word = 0; x.redirect = 0; $$ = make_simple_command (x, (COMMAND *)NULL); $$->flags |= CMD_INVERT_RETURN; /* XXX - let's cheat and push a newline back */ if ($2 == '\n') token_to_read = '\n'; } ;pipeline: pipeline '|' newline_list pipeline { $$ = command_connect ($1, $4, '|'); } | pipeline BAR_AND newline_list pipeline { /* Make cmd1 |& cmd2 equivalent to cmd1 2>&1 | cmd2 */ COMMAND *tc; REDIRECTEE rd, sd; REDIRECT *r; tc = $1->type == cm_simple ? (COMMAND *)$1->value.Simple : $1; sd.dest = 2; rd.dest = 1; r = make_redirection (sd, r_duplicating_output, rd, 0); if (tc->redirects) { register REDIRECT *t; for (t = tc->redirects; t->next; t = t->next) ; t->next = r; } else tc->redirects = r; $$ = command_connect ($1, $4, '|'); } | command { $$ = $1; } ;timespec: TIME { $$ = CMD_TIME_PIPELINE; } | TIME TIMEOPT { $$ = CMD_TIME_PIPELINE|CMD_TIME_POSIX; } | TIME TIMEOPT TIMEIGN { $$ = CMD_TIME_PIPELINE|CMD_TIME_POSIX; } ;%%/* Initial size to allocate for tokens, and the amount to grow them by. */#define TOKEN_DEFAULT_INITIAL_SIZE 496#define TOKEN_DEFAULT_GROW_SIZE 512/* Should we call prompt_again? */#define SHOULD_PROMPT() \ (interactive && (bash_input.type == st_stdin || bash_input.type == st_stream))#if defined (ALIAS)# define expanding_alias() (pushed_string_list && pushed_string_list->expander)#else# define expanding_alias() 0#endif/* Global var is non-zero when end of file has been reached. */int EOF_Reached = 0;#ifdef DEBUGstatic voiddebug_parser (i) int i;{#if YYDEBUG != 0 yydebug = i;#endif}#endif/* yy_getc () returns the next available character from input or EOF. yy_ungetc (c) makes `c' the next character to read. init_yy_io (get, unget, type, location) makes the function GET the installed function for getting the next character, makes UNGET the installed function for un-getting a character, sets the type of stream (either string or file) from TYPE, and makes LOCATION point to where the input is coming from. *//* Unconditionally returns end-of-file. */intreturn_EOF (){ return (EOF);}/* Variable containing the current get and unget functions. See ./input.h for a clearer description. */BASH_INPUT bash_input;/* Set all of the fields in BASH_INPUT to NULL. Free bash_input.name if it is non-null, avoiding a memory leak. */voidinitialize_bash_input (){ bash_input.type = st_none; FREE (bash_input.name); bash_input.name = (char *)NULL; bash_input.location.file = (FILE *)NULL; bash_input.location.string = (char *)NULL; bash_input.getter = (sh_cget_func_t *)NULL; bash_input.ungetter = (sh_cunget_func_t *)NULL;}/* Set the contents of the current bash input stream from GET, UNGET, TYPE, NAME, and LOCATION. */voidinit_yy_io (get, unget, type, name, location) sh_cget_func_t *get; sh_cunget_func_t *unget; enum stream_type type; const char *name; INPUT_STREAM location;{ bash_input.type = type; FREE (bash_input.name); bash_input.name = name ? savestring (name) : (char *)NULL; /* XXX */#if defined (CRAY) memcpy((char *)&bash_input.location.string, (char *)&location.string, sizeof(location));#else bash_input.location = location;#endif bash_input.getter = get; bash_input.ungetter = unget;}char *yy_input_name (){ return (bash_input.name ? bash_input.name : "stdin");}/* Call this to get the next character of input. */static intyy_getc (){ return (*(bash_input.getter)) ();}/* Call this to unget C. That is, to make C the next character to be read. */static intyy_ungetc (c) int c;{ return (*(bash_input.ungetter)) (c);}#if defined (BUFFERED_INPUT)#ifdef INCLUDE_UNUSEDintinput_file_descriptor (){ switch (bash_input.type) { case st_stream: return (fileno (bash_input.location.file)); case st_bstream: return (bash_input.location.buffered_fd); case st_stdin: default: return (fileno (stdin)); }}#endif#endif /* BUFFERED_INPUT *//* **************************************************************** *//* *//* Let input be read from readline (). *//* *//* **************************************************************** */#if defined (READLINE)char *current_readline_prompt = (char *)NULL;char *current_readline_line = (char *)NULL;int current_readline_line_index = 0;static intyy_readline_get (){ SigHandler *old_sigint; int line_len; unsigned char c; if (!current_readline_line) { if (!bash_readline_initialized) initialize_readline ();#if defined (JOB_CONTROL) if (job_control) give_terminal_to (shell_pgrp, 0);#endif /* JOB_CONTROL */ old_sigint = (SigHandler *)IMPOSSIBLE_TRAP_HANDLER; if (signal_is_ignored (SIGINT) == 0) { interrupt_immediately++; old_sigint = (SigHandler *)set_signal_handler (SIGINT, sigint_sighandler); } terminate_immediately = 1; current_readline_line = readline (current_readline_prompt ? current_readline_prompt : ""); terminate_immediately = 0; if (signal_is_ignored (SIGINT) == 0) { interrupt_immediately--; if (old_sigint != IMPOSSIBLE_TRAP_HANDLER) set_signal_handler (SIGINT, old_sigint); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -