📄 parse.y
字号:
c = yy_getc (); /* Ignore null bytes in input. */ if (c == 0) {#if 0 internal_warning ("read_a_line: ignored null byte in input");#endif continue; } /* If there is no more input, then we return NULL. */ if (c == EOF) { if (interactive && bash_input.type == st_stream) clearerr (stdin); if (indx == 0) return ((char *)NULL); c = '\n'; } /* `+2' in case the final character in the buffer is a newline. */ RESIZE_MALLOCED_BUFFER (line_buffer, indx, 2, buffer_size, 128); /* IF REMOVE_QUOTED_NEWLINES is non-zero, we are reading a here document with an unquoted delimiter. In this case, the line will be expanded as if it were in double quotes. We allow a backslash to escape the next character, but we need to treat the backslash specially only if a backslash quoting a backslash-newline pair appears in the line. */ if (pass_next) { line_buffer[indx++] = c; pass_next = 0; } else if (c == '\\' && remove_quoted_newline) { QUIT; peekc = yy_getc (); if (peekc == '\n') { line_number++; continue; /* Make the unquoted \<newline> pair disappear. */ } else { yy_ungetc (peekc); pass_next = 1; line_buffer[indx++] = c; /* Preserve the backslash. */ } } else line_buffer[indx++] = c; if (c == '\n') { line_buffer[indx] = '\0'; return (line_buffer); } }}/* Return a line as in read_a_line (), but insure that the prompt is the secondary prompt. This is used to read the lines of a here document. REMOVE_QUOTED_NEWLINE is non-zero if we should remove newlines quoted with backslashes while reading the line. It is non-zero unless the delimiter of the here document was quoted. */char *read_secondary_line (remove_quoted_newline) int remove_quoted_newline;{ char *ret; int n, c; prompt_string_pointer = &ps2_prompt; if (SHOULD_PROMPT()) prompt_again (); ret = read_a_line (remove_quoted_newline);#if defined (HISTORY) if (ret && remember_on_history && (parser_state & PST_HEREDOC)) { /* To make adding the the here-document body right, we need to rely on history_delimiting_chars() returning \n for the first line of the here-document body and the null string for the second and subsequent lines, so we avoid double newlines. current_command_line_count == 2 for the first line of the body. */ current_command_line_count++; maybe_add_history (ret); }#endif /* HISTORY */ return ret;}/* **************************************************************** *//* *//* YYLEX () *//* *//* **************************************************************** *//* Reserved words. These are only recognized as the first word of a command. */STRING_INT_ALIST word_token_alist[] = { { "if", IF }, { "then", THEN }, { "else", ELSE }, { "elif", ELIF }, { "fi", FI }, { "case", CASE }, { "esac", ESAC }, { "for", FOR },#if defined (SELECT_COMMAND) { "select", SELECT },#endif { "while", WHILE }, { "until", UNTIL }, { "do", DO }, { "done", DONE }, { "in", IN }, { "function", FUNCTION },#if defined (COMMAND_TIMING) { "time", TIME },#endif { "{", '{' }, { "}", '}' }, { "!", BANG },#if defined (COND_COMMAND) { "[[", COND_START }, { "]]", COND_END },#endif#if defined (COPROCESS_SUPPORT) { "coproc", COPROC },#endif { (char *)NULL, 0}};/* other tokens that can be returned by read_token() */STRING_INT_ALIST other_token_alist[] = { /* Multiple-character tokens with special values */ { "--", TIMEIGN }, { "-p", TIMEOPT }, { "&&", AND_AND }, { "||", OR_OR }, { ">>", GREATER_GREATER }, { "<<", LESS_LESS }, { "<&", LESS_AND }, { ">&", GREATER_AND }, { ";;", SEMI_SEMI }, { ";&", SEMI_AND }, { ";;&", SEMI_SEMI_AND }, { "<<-", LESS_LESS_MINUS }, { "<<<", LESS_LESS_LESS }, { "&>", AND_GREATER }, { "&>>", AND_GREATER_GREATER }, { "<>", LESS_GREATER }, { ">|", GREATER_BAR }, { "|&", BAR_AND }, { "EOF", yacc_EOF }, /* Tokens whose value is the character itself */ { ">", '>' }, { "<", '<' }, { "-", '-' }, { "{", '{' }, { "}", '}' }, { ";", ';' }, { "(", '(' }, { ")", ')' }, { "|", '|' }, { "&", '&' }, { "newline", '\n' }, { (char *)NULL, 0}};/* others not listed here: WORD look at yylval.word ASSIGNMENT_WORD look at yylval.word NUMBER look at yylval.number ARITH_CMD look at yylval.word_list ARITH_FOR_EXPRS look at yylval.word_list COND_CMD look at yylval.command*//* These are used by read_token_word, but appear up here so that shell_getc can use them to decide when to add otherwise blank lines to the history. *//* The primary delimiter stack. */struct dstack dstack = { (char *)NULL, 0, 0 };/* A temporary delimiter stack to be used when decoding prompt strings. This is needed because command substitutions in prompt strings (e.g., PS2) can screw up the parser's quoting state. */static struct dstack temp_dstack = { (char *)NULL, 0, 0 };/* Macro for accessing the top delimiter on the stack. Returns the delimiter or zero if none. */#define current_delimiter(ds) \ (ds.delimiter_depth ? ds.delimiters[ds.delimiter_depth - 1] : 0)#define push_delimiter(ds, character) \ do \ { \ if (ds.delimiter_depth + 2 > ds.delimiter_space) \ ds.delimiters = (char *)xrealloc \ (ds.delimiters, (ds.delimiter_space += 10) * sizeof (char)); \ ds.delimiters[ds.delimiter_depth] = character; \ ds.delimiter_depth++; \ } \ while (0)#define pop_delimiter(ds) ds.delimiter_depth--/* Return the next shell input character. This always reads characters from shell_input_line; when that line is exhausted, it is time to read the next line. This is called by read_token when the shell is processing normal command input. *//* This implements one-character lookahead/lookbehind across physical input lines, to avoid something being lost because it's pushed back with shell_ungetc when we're at the start of a line. */static int eol_ungetc_lookahead = 0;static intshell_getc (remove_quoted_newline) int remove_quoted_newline;{ register int i; int c; unsigned char uc; QUIT; if (sigwinch_received) { sigwinch_received = 0; get_new_window_size (0, (int *)0, (int *)0); } if (eol_ungetc_lookahead) { c = eol_ungetc_lookahead; eol_ungetc_lookahead = 0; return (c); }#if defined (ALIAS) || defined (DPAREN_ARITHMETIC) /* If shell_input_line[shell_input_line_index] == 0, but there is something on the pushed list of strings, then we don't want to go off and get another line. We let the code down below handle it. */ if (!shell_input_line || ((!shell_input_line[shell_input_line_index]) && (pushed_string_list == (STRING_SAVER *)NULL)))#else /* !ALIAS && !DPAREN_ARITHMETIC */ if (!shell_input_line || !shell_input_line[shell_input_line_index])#endif /* !ALIAS && !DPAREN_ARITHMETIC */ { line_number++; restart_read: /* Allow immediate exit if interrupted during input. */ QUIT; i = 0; shell_input_line_terminator = 0; /* If the shell is interatctive, but not currently printing a prompt (interactive_shell && interactive == 0), we don't want to print notifies or cleanup the jobs -- we want to defer it until we do print the next prompt. */ if (interactive_shell == 0 || SHOULD_PROMPT()) {#if defined (JOB_CONTROL) /* This can cause a problem when reading a command as the result of a trap, when the trap is called from flush_child. This call had better not cause jobs to disappear from the job table in that case, or we will have big trouble. */ notify_and_cleanup ();#else /* !JOB_CONTROL */ cleanup_dead_jobs ();#endif /* !JOB_CONTROL */ }#if defined (READLINE) if (no_line_editing && SHOULD_PROMPT())#else if (SHOULD_PROMPT())#endif print_prompt (); if (bash_input.type == st_stream) clearerr (stdin); while (1) { c = yy_getc (); /* Allow immediate exit if interrupted during input. */ QUIT; if (c == '\0') {#if 0 internal_warning ("shell_getc: ignored null byte in input");#endif continue; } RESIZE_MALLOCED_BUFFER (shell_input_line, i, 2, shell_input_line_size, 256); if (c == EOF) { if (bash_input.type == st_stream) clearerr (stdin); if (i == 0) shell_input_line_terminator = EOF; shell_input_line[i] = '\0'; break; } shell_input_line[i++] = c; if (c == '\n') { shell_input_line[--i] = '\0'; current_command_line_count++; break; } } shell_input_line_index = 0; shell_input_line_len = i; /* == strlen (shell_input_line) */ set_line_mbstate ();#if defined (HISTORY) if (remember_on_history && shell_input_line && shell_input_line[0]) { char *expansions;# if defined (BANG_HISTORY) int old_hist; /* If the current delimiter is a single quote, we should not be performing history expansion, even if we're on a different line from the original single quote. */ old_hist = history_expansion_inhibited; if (current_delimiter (dstack) == '\'') history_expansion_inhibited = 1;# endif expansions = pre_process_line (shell_input_line, 1, 1);# if defined (BANG_HISTORY) history_expansion_inhibited = old_hist;# endif if (expansions != shell_input_line) { free (shell_input_line); shell_input_line = expansions; shell_input_line_len = shell_input_line ? strlen (shell_input_line) : 0; if (shell_input_line_len == 0) current_command_line_count--; /* We have to force the xrealloc below because we don't know the true allocated size of shell_input_line anymore. */ shell_input_line_size = shell_input_line_len; set_line_mbstate (); } } /* Try to do something intelligent with blank lines encountered while entering multi-line commands. XXX - this is grotesque */ else if (remember_on_history && shell_input_line && shell_input_line[0] == '\0' && current_command_line_count > 1) { if (current_delimiter (dstack)) /* We know shell_input_line[0] == 0 and we're reading some sort of quoted string. This means we've got a line consisting of only a newline in a quoted string. We want to make sure this line gets added to the history. */ maybe_add_history (shell_input_line); else { char *hdcs; hdcs = history_delimiting_chars (shell_input_line); if (hdcs && hdcs[0] == ';') maybe_add_history (shell_input_line); } }#endif /* HISTORY */ if (shell_input_line) { /* Lines that signify the end of the shell's input should not be echoed. */ if (echo_input_at_read && (shell_input_line[0] || shell_input_line_terminator != EOF)) fprintf (stderr, "%s\n", shell_input_line); } else { shell_input_line_size = 0; prompt_string_pointer = ¤t_prompt_string; if (SHOULD_PROMPT ()) prompt_again (); goto restart_read; } /* Add the newline to the end of this string, iff the string does not already end in an EOF character. */ if (shell_input_line_terminator != EOF) { if (shell_input_line_len + 3 > shell_input_line_size) shell_input_line = (char *)xrealloc (shell_input_line, 1 + (shell_input_line_size += 2)); shell_input_line[shell_input_line_len] = '\n'; shell_input_line[shell_input_line_len + 1] = '\0'; set_line_mbstate (); } }next_alias_char: uc = shell_input_line[shell_input_line_index]; if (uc) shell_input_line_index++;#if defined (ALIAS) || defined (DPAREN_ARITHMETIC) /* If UC is NULL, we have reached the end of the current input string. If pushed_string_list is non-empty, it's time to pop to the previous string because we have fully consumed the result of the last alias expansion. Do it transparently; just return the next character of the string popped to. */pop_alias: if (uc == 0 && (pushed_string_list != (STRING_SAVER *)NULL)) { pop_string (); uc = shell_input_line[shell_input_line_index]; if (uc) shell_input_line_index++; }#endif /* ALIAS || DPAREN_ARITHMETIC */ if MBTEST(uc == '\\' && remove_quoted_newline && shell_input_line[shell_input_line_index] == '\n') { if (SHOULD_PROMPT ()) prompt_again (); line_number++; /* What do we do here if we're expanding an alias whose definition includes an escaped newline? If that's the last character in the alias expansion, we just pop the pushed string list (recall that we inhibit the appending of a space in mk_alexpansion() if newline is the last character). If it's not the last character, we need to consume the quoted newline and move to the next character in the expansion. */ if (expanding_alias () && shell_input_line[shell_input_line_index+1] == '\0') { uc = 0; goto pop_alias; } else if (expanding_alias () && shell_input_line[shell_input_line_index+1] != '\0') { shell_input_line_index++; /* skip newline */ goto next_alias_char; /* and get next character */ } else goto restart_read; } if (uc == 0 && shell_input_line_terminator == EOF) return ((shell_input_line_index != 0) ? '\n' : EOF); return (uc);}/* Put C back into the input for the shell. This might need changes for HANDLE_MULTIBYTE around EOLs. Since we (currently) never push
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -