📄 parse.y
字号:
#if 0 /* Reset the prompt to the decoded value of prompt_string_pointer. */ reset_readline_prompt ();#endif if (current_readline_line == 0) return (EOF); current_readline_line_index = 0; line_len = strlen (current_readline_line); current_readline_line = (char *)xrealloc (current_readline_line, 2 + line_len); current_readline_line[line_len++] = '\n'; current_readline_line[line_len] = '\0'; } if (current_readline_line[current_readline_line_index] == 0) { free (current_readline_line); current_readline_line = (char *)NULL; return (yy_readline_get ()); } else { c = current_readline_line[current_readline_line_index++]; return (c); }}static intyy_readline_unget (c) int c;{ if (current_readline_line_index && current_readline_line) current_readline_line[--current_readline_line_index] = c; return (c);}voidwith_input_from_stdin (){ INPUT_STREAM location; if (bash_input.type != st_stdin && stream_on_stack (st_stdin) == 0) { location.string = current_readline_line; init_yy_io (yy_readline_get, yy_readline_unget, st_stdin, "readline stdin", location); }}#else /* !READLINE */voidwith_input_from_stdin (){ with_input_from_stream (stdin, "stdin");}#endif /* !READLINE *//* **************************************************************** *//* *//* Let input come from STRING. STRING is zero terminated. *//* *//* **************************************************************** */static intyy_string_get (){ register char *string; register unsigned char c; string = bash_input.location.string; /* If the string doesn't exist, or is empty, EOF found. */ if (string && *string) { c = *string++; bash_input.location.string = string; return (c); } else return (EOF);}static intyy_string_unget (c) int c;{ *(--bash_input.location.string) = c; return (c);}voidwith_input_from_string (string, name) char *string; const char *name;{ INPUT_STREAM location; location.string = string; init_yy_io (yy_string_get, yy_string_unget, st_string, name, location);}/* Count the number of characters we've consumed from bash_input.location.string and read into shell_input_line, but have not returned from shell_getc. That is the true input location. Rewind bash_input.location.string by that number of characters, so it points to the last character actually consumed by the parser. */static voidrewind_input_string (){ int xchars; /* number of unconsumed characters in the input -- XXX need to take newlines into account, e.g., $(...\n) */ xchars = shell_input_line_len - shell_input_line_index; if (bash_input.location.string[-1] == '\n') xchars++; /* XXX - how to reflect bash_input.location.string back to string passed to parse_and_execute or xparse_dolparen? xparse_dolparen needs to know how far into the string we parsed. parse_and_execute knows where bash_input. location.string is, and how far from orig_string that is -- that's the number of characters the command consumed. */ /* bash_input.location.string - xchars should be where we parsed to */ /* need to do more validation on xchars value for sanity -- test cases. */ bash_input.location.string -= xchars;}/* **************************************************************** *//* *//* Let input come from STREAM. *//* *//* **************************************************************** *//* These two functions used to test the value of the HAVE_RESTARTABLE_SYSCALLS define, and just use getc/ungetc if it was defined, but since bash installs its signal handlers without the SA_RESTART flag, some signals (like SIGCHLD, SIGWINCH, etc.) received during a read(2) will not cause the read to be restarted. We need to restart it ourselves. */static intyy_stream_get (){ int result; result = EOF; if (bash_input.location.file) { if (interactive) { interrupt_immediately++; terminate_immediately++; } result = getc_with_restart (bash_input.location.file); if (interactive) { interrupt_immediately--; terminate_immediately--; } } return (result);}static intyy_stream_unget (c) int c;{ return (ungetc_with_restart (c, bash_input.location.file));}voidwith_input_from_stream (stream, name) FILE *stream; const char *name;{ INPUT_STREAM location; location.file = stream; init_yy_io (yy_stream_get, yy_stream_unget, st_stream, name, location);}typedef struct stream_saver { struct stream_saver *next; BASH_INPUT bash_input; int line;#if defined (BUFFERED_INPUT) BUFFERED_STREAM *bstream;#endif /* BUFFERED_INPUT */} STREAM_SAVER;/* The globally known line number. */int line_number = 0;/* The line number offset set by assigning to LINENO. Not currently used. */int line_number_base = 0;#if defined (COND_COMMAND)static int cond_lineno;static int cond_token;#endifSTREAM_SAVER *stream_list = (STREAM_SAVER *)NULL;voidpush_stream (reset_lineno) int reset_lineno;{ STREAM_SAVER *saver = (STREAM_SAVER *)xmalloc (sizeof (STREAM_SAVER)); xbcopy ((char *)&bash_input, (char *)&(saver->bash_input), sizeof (BASH_INPUT));#if defined (BUFFERED_INPUT) saver->bstream = (BUFFERED_STREAM *)NULL; /* If we have a buffered stream, clear out buffers[fd]. */ if (bash_input.type == st_bstream && bash_input.location.buffered_fd >= 0) saver->bstream = set_buffered_stream (bash_input.location.buffered_fd, (BUFFERED_STREAM *)NULL);#endif /* BUFFERED_INPUT */ saver->line = line_number; bash_input.name = (char *)NULL; saver->next = stream_list; stream_list = saver; EOF_Reached = 0; if (reset_lineno) line_number = 0;}voidpop_stream (){ if (!stream_list) EOF_Reached = 1; else { STREAM_SAVER *saver = stream_list; EOF_Reached = 0; stream_list = stream_list->next; init_yy_io (saver->bash_input.getter, saver->bash_input.ungetter, saver->bash_input.type, saver->bash_input.name, saver->bash_input.location);#if defined (BUFFERED_INPUT) /* If we have a buffered stream, restore buffers[fd]. */ /* If the input file descriptor was changed while this was on the save stack, update the buffered fd to the new file descriptor and re-establish the buffer <-> bash_input fd correspondence. */ if (bash_input.type == st_bstream && bash_input.location.buffered_fd >= 0) { if (bash_input_fd_changed) { bash_input_fd_changed = 0; if (default_buffered_input >= 0) { bash_input.location.buffered_fd = default_buffered_input; saver->bstream->b_fd = default_buffered_input; SET_CLOSE_ON_EXEC (default_buffered_input); } } /* XXX could free buffered stream returned as result here. */ set_buffered_stream (bash_input.location.buffered_fd, saver->bstream); }#endif /* BUFFERED_INPUT */ line_number = saver->line; FREE (saver->bash_input.name); free (saver); }}/* Return 1 if a stream of type TYPE is saved on the stack. */intstream_on_stack (type) enum stream_type type;{ register STREAM_SAVER *s; for (s = stream_list; s; s = s->next) if (s->bash_input.type == type) return 1; return 0;}/* Save the current token state and return it in a malloced array. */int *save_token_state (){ int *ret; ret = (int *)xmalloc (4 * sizeof (int)); ret[0] = last_read_token; ret[1] = token_before_that; ret[2] = two_tokens_ago; ret[3] = current_token; return ret;}voidrestore_token_state (ts) int *ts;{ if (ts == 0) return; last_read_token = ts[0]; token_before_that = ts[1]; two_tokens_ago = ts[2]; current_token = ts[3];}/* * This is used to inhibit alias expansion and reserved word recognition * inside case statement pattern lists. A `case statement pattern list' is: * * everything between the `in' in a `case word in' and the next ')' * or `esac' * everything between a `;;' and the next `)' or `esac' */#if defined (ALIAS) || defined (DPAREN_ARITHMETIC)#define END_OF_ALIAS 0/* * Pseudo-global variables used in implementing token-wise alias expansion. *//* * Pushing and popping strings. This works together with shell_getc to * implement alias expansion on a per-token basis. */typedef struct string_saver { struct string_saver *next; int expand_alias; /* Value to set expand_alias to when string is popped. */ char *saved_line;#if defined (ALIAS) alias_t *expander; /* alias that caused this line to be pushed. */#endif int saved_line_size, saved_line_index, saved_line_terminator;} STRING_SAVER;STRING_SAVER *pushed_string_list = (STRING_SAVER *)NULL;/* * Push the current shell_input_line onto a stack of such lines and make S * the current input. Used when expanding aliases. EXPAND is used to set * the value of expand_next_token when the string is popped, so that the * word after the alias in the original line is handled correctly when the * alias expands to multiple words. TOKEN is the token that was expanded * into S; it is saved and used to prevent infinite recursive expansion. */static voidpush_string (s, expand, ap) char *s; int expand; alias_t *ap;{ STRING_SAVER *temp = (STRING_SAVER *)xmalloc (sizeof (STRING_SAVER)); temp->expand_alias = expand; temp->saved_line = shell_input_line; temp->saved_line_size = shell_input_line_size; temp->saved_line_index = shell_input_line_index; temp->saved_line_terminator = shell_input_line_terminator;#if defined (ALIAS) temp->expander = ap;#endif temp->next = pushed_string_list; pushed_string_list = temp;#if defined (ALIAS) if (ap) ap->flags |= AL_BEINGEXPANDED;#endif shell_input_line = s; shell_input_line_size = strlen (s); shell_input_line_index = 0; shell_input_line_terminator = '\0';#if 0 parser_state &= ~PST_ALEXPNEXT; /* XXX */#endif set_line_mbstate ();}/* * Make the top of the pushed_string stack be the current shell input. * Only called when there is something on the stack. Called from shell_getc * when it thinks it has consumed the string generated by an alias expansion * and needs to return to the original input line. */static voidpop_string (){ STRING_SAVER *t; FREE (shell_input_line); shell_input_line = pushed_string_list->saved_line; shell_input_line_index = pushed_string_list->saved_line_index; shell_input_line_size = pushed_string_list->saved_line_size; shell_input_line_terminator = pushed_string_list->saved_line_terminator; if (pushed_string_list->expand_alias) parser_state |= PST_ALEXPNEXT; else parser_state &= ~PST_ALEXPNEXT; t = pushed_string_list; pushed_string_list = pushed_string_list->next;#if defined (ALIAS) if (t->expander) t->expander->flags &= ~AL_BEINGEXPANDED;#endif free ((char *)t); set_line_mbstate ();}static voidfree_string_list (){ register STRING_SAVER *t, *t1; for (t = pushed_string_list; t; ) { t1 = t->next; FREE (t->saved_line);#if defined (ALIAS) if (t->expander) t->expander->flags &= ~AL_BEINGEXPANDED;#endif free ((char *)t); t = t1; } pushed_string_list = (STRING_SAVER *)NULL;}#endif /* ALIAS || DPAREN_ARITHMETIC */voidfree_pushed_string_input (){#if defined (ALIAS) || defined (DPAREN_ARITHMETIC) free_string_list ();#endif}/* Return a line of text, taken from wherever yylex () reads input. If there is no more input, then we return NULL. If REMOVE_QUOTED_NEWLINE is non-zero, we remove unquoted \<newline> pairs. This is used by read_secondary_line to read here documents. */static char *read_a_line (remove_quoted_newline) int remove_quoted_newline;{ static char *line_buffer = (char *)NULL; static int buffer_size = 0; int indx, c, peekc, pass_next;#if defined (READLINE) if (no_line_editing && SHOULD_PROMPT ())#else if (SHOULD_PROMPT ())#endif print_prompt (); pass_next = indx = 0; while (1) { /* Allow immediate exit if interrupted during input. */ QUIT;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -