Exemplo n.º 1
0
/*
 * command_line_parse(parsestate, in_parens)
 *
 *   Parses a command line from 'input' into a linked list of command_t
 *   structures. The head of the linked list is returned, or NULL is
 *   returned on error.
 *   If 'in_parens != 0', then command_line_parse() is being called recursively
 *   from command_parse().  A right parenthesis should end the "command line".
 *   But at the top-level command line, when 'in_parens == 0', a right
 *   parenthesis is an error.
 */
command_t *
command_line_parse(parsestate_t *parsestate, int in_parens)
{
	command_t *prev_cmd = NULL;
	command_t *head = NULL;
	command_t *cmd;
	token_t token;
	int r;

	// This loop has to deal with command syntax in a smart way.
	// Here's a non exhaustive list of the behavior it should implement
	// when 'in_parens == 0'.

	// COMMAND                             => OK
	// COMMAND ;                           => OK
	// COMMAND && COMMAND                  => OK
	// COMMAND &&                          => error (can't end with &&)
	// COMMAND )                           => error (but OK if "in_parens")
	
	while (1) {
		// Parse the next command.
		cmd = command_parse(parsestate);
		if (!cmd)		// Empty commands are errors.
			goto error;

		// Link the command up to the command line.
		if (prev_cmd)
			prev_cmd->next = cmd;
		else
			head = cmd;
		prev_cmd = cmd;

		// EXERCISE: Fetch the next token to see how to connect this
		// command with the next command.  React to errors with
		// 'goto error'.  The ";" and "&" tokens may require special
		// handling, since unlike other special tokens, they can end
		// the command line.
		parse_gettoken(parsestate, &token);
		if (token.type == TOK_NORMAL)
			printf("parse token error");
		cmd->controlop = token.type;
		/* Your code here */

		switch (token.type) {
		case TOK_SEMICOLON:
		case TOK_AMPERSAND:
			parse_gettoken(parsestate, &token);
			if (token.type != TOK_END)
				parse_ungettoken(parsestate);
			else
				goto done;
			break;
		case TOK_CLOSE_PAREN:
			if (in_parens == PARENS_IN) {
				cmd->controlop = CMD_END;
				goto done;
			} else
				goto error;
			break;
		case TOK_END:
			goto done;
		default:
			;
		}
	}

 done:
	// EXERCISE: Check that the command line ends properly.
/* 	 if (in_parens == PARENS_OUT) {
 		 if (strlen(parsestate->position) != 0) {
 			 printf("strlen %d\n", strlen(parsestate->position));
 			 perror("line end error");
 			 exit(1);
 		 }
 	 }*/
	/* Your code here */

	return head;

 error:
	command_free(head);
	return NULL;
}
Exemplo n.º 2
0
command_t *
command_parse(parsestate_t *parsestate)
{
	int i = 0;
	command_t *cmd = command_alloc();
	if (!cmd)
	{
		printf("cmd alloc error\n");
		return NULL;
	}

	while (1) {
		// EXERCISE: Read the next token from 'parsestate'.

		// Normal tokens go in the cmd->argv[] array.
		// Redirection file names go into cmd->redirect_filename[].
		// Open parenthesis tokens indicate a subshell command.
		// Other tokens complete the current command
		// and are not actually part of it;
		// use parse_ungettoken() to save those tokens for later.

		// There are a couple errors you should check.
		// First, be careful about overflow on normal tokens.
		// Each command_t only has space for MAXTOKENS tokens in
		// 'argv'. If there are too many tokens, reject the whole
		// command.
		// Second, redirection tokens (<, >, 2>) must be followed by
		// TOK_NORMAL tokens containing file names.
		// Third, a parenthesized subcommand can't be part of the
		// same command as other normal tokens.  For example,
		// "echo ( echo foo )" and "( echo foo ) echo" are both errors.
		// (You should figure out exactly how to check for this kind
		// of error. Try interacting with the actual 'bash' shell
		// for some ideas.)
		// 'goto error' when you encounter one of these errors,
		// which frees the current command and returns NULL.

		// Hint: An open parenthesis should recursively call
		// command_line_parse(). The command_t structure has a slot
		// you can use for parens; figure out how to use it!

		if (i > MAXTOKENS)
			goto error;

		token_t token;
		parse_gettoken(parsestate, &token);

		switch (token.type) {
		case TOK_NORMAL:
			//printf("%s len: %d", token.buffer, strlen(token.buffer));
			if (cmd->subshell != NULL) {
				parse_ungettoken(parsestate);
				goto done;
			}
			if (strlen(token.buffer) != 0) {
				cmd->argv[i] = strdup(token.buffer);
				i++;
			}
			break;
		case TOK_LESS_THAN:
			//printf("input red\n");
			parse_gettoken(parsestate, &token);
			if (token.type != TOK_NORMAL)
				goto error;
			cmd->redirect_filename[0] = strdup(token.buffer);
						break;
		case TOK_GREATER_THAN:
			//printf("output red\n");
			parse_gettoken(parsestate, &token);
			if (token.type != TOK_NORMAL)
				goto error;
			cmd->redirect_filename[1] = strdup(token.buffer);
						break;
		case TOK_2_GREATER_THAN:
			//printf("stderr red\n");
			parse_gettoken(parsestate, &token);
			if (token.type != TOK_NORMAL)
				goto error;
			cmd->redirect_filename[2] = strdup(token.buffer);
			break;
		case TOK_OPEN_PAREN:
			cmd->subshell = command_line_parse(parsestate, PARENS_IN);
			//goto done;
			break;
		case TOK_CLOSE_PAREN:
		default:
			parse_ungettoken(parsestate);
			goto done;
		}
	}

 done:
	// NULL-terminate the argv list
	cmd->argv[i] = 0;

	// EXERCISE: Make sure you return the right return value!

	if (i == 0 && cmd->subshell == NULL) {
		/* Empty command */
		command_free(cmd);
		return NULL;
	} else
		return cmd;
	
 error:
	command_free(cmd);
	return NULL;
}
Exemplo n.º 3
0
/*
 * cmd_line_parse(parsestate, in_parens)
 *
 *   Parses a command line from 'input' into a linked list of command_t
 *   structures. The head of the linked list is returned, or NULL is
 *   returned on error.
 *   If 'in_parens != 0', then cmd_line_parse() is being called recursively
 *   from cmd_parse().  A right parenthesis should end the "command line".
 *   But at the top-level command line, when 'in_parens == 0', a right
 *   parenthesis is an error.
 */
command_t *
cmd_line_parse(parsestate_t *parsestate, int in_parens)
{
	command_t *prev_cmd = NULL;
	command_t *head = NULL;
	command_t *cmd;
	token_t token;
	int r;

	// This loop has to deal with command syntax in a smart way.
	// Here's a nonexhaustive list of the behavior it should implement
	// when 'in_parens == 0'.

	// COMMAND                             => OK
	// COMMAND ;                           => OK
	// COMMAND && COMMAND                  => OK
	// COMMAND &&                          => error (can't end with &&)
	// COMMAND )                           => error (but OK if "in_parens")

	while (1) {
		// Parse the next command.
		cmd = cmd_parse(parsestate);
		if (!cmd)		// Empty commands are errors.
			goto error;

		if (prev_cmd)
			prev_cmd->next = cmd;
		else
			head = cmd;
		prev_cmd = cmd;

		// Fetch the next token to see how to connect this
		// command with the next command.  React to errors with
		// 'goto error'.  The ";" and "&" tokens require special
		// handling, since unlike other special tokens, they can end
		// the command line.

		parse_gettoken(parsestate, &token);
		switch (token.type) {
		case TOK_DOUBLEAMP:
		case TOK_DOUBLEPIPE:
		case TOK_PIPE:
			cmd->controlop = token.type;
			break;

		case TOK_SEMICOLON:
		case TOK_AMPERSAND:
			cmd->controlop = token.type;
			parse_gettoken(parsestate, &token);
			if (token.type == TOK_END || token.type == TOK_CLOSE_PAREN)
				goto ender;
			parse_ungettoken(parsestate);
			break;

		ender:
		case TOK_END:
		case TOK_CLOSE_PAREN:
			if ((token.type == TOK_END) == (in_parens != 0))
				goto error;
			goto done;

		default:
			goto error;
		}
	}

 done:
	// Check that the command line ends properly.
	if (prev_cmd
	    && prev_cmd->controlop != CMD_END
	    && prev_cmd->controlop != CMD_SEMICOLON
	    && prev_cmd->controlop != CMD_BACKGROUND)
		goto error;

	return head;

 error:
	cmd_free(head);
	return NULL;
}
Exemplo n.º 4
0
command_t *
command_parse(parsestate_t *parsestate)
{
	int i = 0;
	command_t *cmd = command_alloc();
	if (!cmd)
		return NULL;

	int flag_in=0;
	int flag_out=0;
	int flag_err=0;
	while (1) {
		// EXERCISE: Read the next token from 'parsestate'.

		// Normal tokens go in the cmd->argv[] array.
		// Redirection file names go into cmd->redirect_filename[].
		// Open parenthesis tokens indicate a subshell command.
		// Other tokens complete the current command
		// and are not actually part of it;
		// use parse_ungettoken() to save those tokens for later.

		// There are a couple errors you should check.
		// First, be careful about overflow on normal tokens.
		// Each command_t only has space for MAXTOKENS tokens in
		// 'argv'. If there are too many tokens, reject the whole
		// command.
		// Second, redirection tokens (<, >, 2>) must be followed by
		// TOK_NORMAL tokens containing file names.
		// Third, a parenthesized subcommand can't be part of the
		// same command as other normal tokens.  For example,
		// "echo ( echo foo )" and "( echo foo ) echo" are both errors.
		// (You should figure out exactly how to check for this kind
		// of error. Try interacting with the actual 'bash' shell
		// for some ideas.)
		// 'goto error' when you encounter one of these errors,
		// which frees the current command and returns NULL.

		// Hint: An open parenthesis should recursively call
		// command_line_parse(). The command_t structure has a slot
		// you can use for parens; figure out how to use it!

		token_t token;
		memset(&token, 0, sizeof(token));
		parse_gettoken(parsestate, &token);


		switch (token.type) {
		case TOK_NORMAL:
			if(flag_out){
				flag_out=0;
				cmd->redirect_filename[1]=strdup(token.buffer);
				break;
			}
			else if(flag_in){
				flag_in=0;
				cmd->redirect_filename[0]=strdup(token.buffer);
				break;
			}
			else if(flag_err){
				flag_err=0;
				cmd->redirect_filename[2]=strdup(token.buffer);
				break;
			}
			if(i==MAXTOKENS) goto error;
			cmd->argv[i] = strdup(token.buffer);
			i++;
			break;
		case TOK_PIPE:
			cmd->controlop=CMD_PIPE;
			parse_ungettoken(parsestate);
			goto done;
		case TOK_DOUBLEPIPE:
			cmd->controlop=CMD_OR;
			parse_ungettoken(parsestate);
			goto done;
		case TOK_AMPERSAND:
			cmd->controlop=CMD_BACKGROUND;
			parse_ungettoken(parsestate);
			goto done;
		case TOK_DOUBLEAMP:
			cmd->controlop=CMD_AND;
			parse_ungettoken(parsestate);
			goto done;
		case TOK_SEMICOLON:
			cmd->controlop=CMD_SEMICOLON;
			parse_ungettoken(parsestate);
			goto done;
		case TOK_OPEN_PAREN:
			cmd->subshell=command_line_parse(parsestate,1);
			break;
		case TOK_CLOSE_PAREN:
			parse_ungettoken(parsestate);
			goto done;
		case TOK_END:
			parse_ungettoken(parsestate);
			cmd->controlop=CMD_END;
			goto done;
		case TOK_ERROR:
			goto error;
		case TOK_GREATER_THAN:
			flag_out=1;
			break;
		case TOK_LESS_THAN:
			flag_in=1;
			break;
		case TOK_2_GREATER_THAN:
			flag_err=1;
			break;
		default:
			parse_ungettoken(parsestate);
			goto done;
		}
	}

 done:
	// NULL-terminate the argv list
	cmd->argv[i] = 0;

	// EXERCISE: Make sure you return the right return value!

	if (i == 0 && cmd->subshell==NULL) {
		/* Empty command */
		command_free(cmd);
		return NULL;
	} else
		return cmd;
	
 error:
	command_free(cmd);
	return NULL;
}
Exemplo n.º 5
0
command_t *
cmd_parse(parsestate_t *parsestate)
{
	int i = 0;
	command_t *cmd = cmd_alloc();
	if (!cmd)
		return NULL;

	while (1) {

		// Read the next token from 'parsestate'.
		token_t token;
		parse_gettoken(parsestate, &token);

		// Normal tokens go in the cmd->argv[] array.
		// Redirection file names go into cmd->redirect_filename[].
		// Open parenthesis tokens indicate a subshell command.
		// Other tokens complete the current command
		// and are not actually part of it;
		// we use parse_ungettoken() to save those tokens for later.

		switch (token.type) {
		case TOK_NORMAL:
                    // Overflow on normal tokens
			if (i >= MAXTOKENS || cmd->subshell)
				goto error;
			cmd->argv[i] = strdup(token.buffer);
			i++;
			break;
		case TOK_LESS_THAN:
		case TOK_GREATER_THAN:
		case TOK_2_GREATER_THAN: {
			int fd = token.type - TOK_LESS_THAN;
			// Can't redirect nothing
			if (i == 0 && !cmd->subshell)
				goto error;
            // Redirection tokens (<, >, 2>) must be followed by
            // TOK_NORMAL tokens containing file names.
			parse_gettoken(parsestate, &token);
			if (token.type != TOK_NORMAL)
				goto error;
			free(cmd->redirect_filename[fd]);
			cmd->redirect_filename[fd] = strdup(token.buffer);
			break;
		}
		case TOK_OPEN_PAREN:

             // EXERCISE: Handle parentheses.
             // NOTE the following:
             //     --Parentheses in the shell do not act like
             //     mathematical parentheses.
             //     --In particular, a parenthesized subcommand cannot
             //     be part of the same command as other normal tokens.
             //     For example, "echo ( echo foo )",
             //                  "( echo foo ) echo", and
             //                  "(echo foo) (echo foo)"
             //
             //     are all syntax errors.  (You should figure out
             //     exactly how to check for this kind of error. Try
             //     interacting with the actual 'bash' shell for some
             //     ideas.)
             //
             // Some hints for the code:
             //     --An open parenthesis should recursively call
             //     cmd_line_parse(). The command_t structure has a slot
             //     you can use.
             //     --'goto error' when you encounter an error,
             //     which frees the current command and returns NULL.
             //     --You will need to adjust the logic in the "done:"
             //     block, below. Otherwise, a subshell will be regarded as
             //     an error (why?)
             //     --You don't have to write a lot of code here, but
             //     you will have to understand how the pieces that you
             //     have been given fit together. (It may be helpful to
             //     look over cmdparse.h again.)
            /* Your code here. */
			cmd->subshell = cmd_line_parse(parsestate, 1);
			if(!cmd->subshell){
				goto error;
			}

			break;
		default:
			parse_ungettoken(parsestate);
			goto done;
		}
	}

 done:
	// NULL-terminate the argv list
	cmd->argv[i] = 0;

	if (i == 0 && !cmd->subshell) {
		/* Empty command */
		cmd_free(cmd);
		return NULL;
	} else
		return cmd;

 error:
	cmd_free(cmd);
	return NULL;
}