Merging HW4_CODE
This commit is contained in:
		
						commit
						9c7b99693b
					
				
							
								
								
									
										7
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| 
						 | 
					@ -1,4 +1,7 @@
 | 
				
			||||||
bin/
 | 
					 | 
				
			||||||
build/
 | 
					 | 
				
			||||||
*~
 | 
					*~
 | 
				
			||||||
 | 
					#*
 | 
				
			||||||
 | 
					*.d
 | 
				
			||||||
 | 
					*.o
 | 
				
			||||||
*.out
 | 
					*.out
 | 
				
			||||||
 | 
					bin/*
 | 
				
			||||||
 | 
					build/*
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,10 +1,8 @@
 | 
				
			||||||
image: hwrunner:latest
 | 
					image: hwrunner:latest
 | 
				
			||||||
variables:
 | 
					variables:
 | 
				
			||||||
    GIT_SSL_NO_VERIFY: "true"
 | 
					    GIT_SSL_NO_VERIFY: "true"
 | 
				
			||||||
    EXEC: sfmm
 | 
					    EXEC: mush
 | 
				
			||||||
    HW_DIR: hw3
 | 
					    HW_DIR: hw4
 | 
				
			||||||
    CPU_LIMIT: 60
 | 
					 | 
				
			||||||
    FILE_LIMIT: 1000000
 | 
					 | 
				
			||||||
before_script:
 | 
					before_script:
 | 
				
			||||||
    - make clean all -C ${HW_DIR}
 | 
					    - make clean all -C ${HW_DIR}
 | 
				
			||||||
stages:
 | 
					stages:
 | 
				
			||||||
| 
						 | 
					@ -18,12 +16,8 @@ build:
 | 
				
			||||||
run:
 | 
					run:
 | 
				
			||||||
    stage: run
 | 
					    stage: run
 | 
				
			||||||
    script:
 | 
					    script:
 | 
				
			||||||
        - ulimit -t ${CPU_LIMIT}
 | 
					        - cd ${HW_DIR} && bin/${EXEC} < rsrc/run_test.mush
 | 
				
			||||||
        - ulimit -f ${FILE_LIMIT}
 | 
					 | 
				
			||||||
        - cd ${HW_DIR} && bin/${EXEC}
 | 
					 | 
				
			||||||
test:
 | 
					test:
 | 
				
			||||||
    stage: test
 | 
					    stage: test
 | 
				
			||||||
    script:
 | 
					    script:
 | 
				
			||||||
        - ulimit -t ${CPU_LIMIT}
 | 
					        - cd ${HW_DIR} && bin/${EXEC}_tests -S --verbose=0 --timeout 5
 | 
				
			||||||
        - ulimit -f ${FILE_LIMIT}
 | 
					 | 
				
			||||||
        - cd ${HW_DIR} && bin/${EXEC}_tests -S --verbose=0 --timeout 30
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										61
									
								
								hw4/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								hw4/Makefile
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,61 @@
 | 
				
			||||||
 | 
					CC := gcc
 | 
				
			||||||
 | 
					YACC := bison
 | 
				
			||||||
 | 
					LEX := flex
 | 
				
			||||||
 | 
					SRCD := src
 | 
				
			||||||
 | 
					TSTD := tests
 | 
				
			||||||
 | 
					BLDD := build
 | 
				
			||||||
 | 
					BIND := bin
 | 
				
			||||||
 | 
					INCD := include
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					MAIN  := $(BLDD)/main.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ALL_SRCF := $(shell find $(SRCD) -type f -name *.c)
 | 
				
			||||||
 | 
					ALL_OBJF := $(patsubst $(SRCD)/%,$(BLDD)/%,$(ALL_SRCF:.c=.o))
 | 
				
			||||||
 | 
					ALL_FUNCF := $(filter-out $(MAIN) $(AUX), $(ALL_OBJF))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST_SRC := $(shell find $(TSTD) -type f -name *.c)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					INC := -I $(INCD)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CFLAGS := -Wall -Werror -Wno-unused-function -MMD
 | 
				
			||||||
 | 
					COLORF := -DCOLOR
 | 
				
			||||||
 | 
					DFLAGS := -g -DDEBUG -DCOLOR
 | 
				
			||||||
 | 
					PRINT_STAMENTS := -DERROR -DSUCCESS -DWARN -DINFO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST_LIB := -lcriterion
 | 
				
			||||||
 | 
					LIBS :=
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					EXEC := mush
 | 
				
			||||||
 | 
					TEST_EXEC := $(EXEC)_tests
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.PHONY: clean all setup debug
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					all: setup $(BIND)/$(EXEC) $(BIND)/$(TEST_EXEC)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					debug: CFLAGS += $(DFLAGS) $(PRINT_STAMENTS) $(COLORF)
 | 
				
			||||||
 | 
					debug: all
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					setup: $(BIND) $(BLDD)
 | 
				
			||||||
 | 
					$(BIND):
 | 
				
			||||||
 | 
						mkdir -p $(BIND)
 | 
				
			||||||
 | 
					$(BLDD):
 | 
				
			||||||
 | 
						mkdir -p $(BLDD)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(BIND)/$(EXEC): $(BLDD)/mush.tab.o $(BLDD)/mush.lex.o $(ALL_OBJF)
 | 
				
			||||||
 | 
						$(CC) $^ -o $@ $(LIBS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(BIND)/$(TEST_EXEC): $(ALL_FUNCF) $(BLDD)/mush.tab.o $(BLDD)/mush.lex.o $(TEST_SRC)
 | 
				
			||||||
 | 
						$(CC) $(CFLAGS) $(INC) $(ALL_FUNCF) $(TEST_SRC) $(TEST_LIB) $(LIBS) -o $@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(BLDD)/%.o: $(SRCD)/%.c $(INCD)/$(EXEC).tab.h
 | 
				
			||||||
 | 
						$(CC) $(CFLAGS) $(INC) -c -o $@ $<
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					clean:
 | 
				
			||||||
 | 
						rm -rf $(BLDD) $(BIND)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Cancel the implicit rule that is doing the wrong thing.
 | 
				
			||||||
 | 
					%.c: %.y
 | 
				
			||||||
 | 
					%.c: %.l
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.PRECIOUS: $(BLDD)/*.d
 | 
				
			||||||
 | 
					-include $(BLDD)/*.d
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								hw4/demo/mush
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								hw4/demo/mush
									
									
									
									
									
										Executable file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										88
									
								
								hw4/include/debug.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								hw4/include/debug.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,88 @@
 | 
				
			||||||
 | 
					#ifndef DEBUG_H
 | 
				
			||||||
 | 
					#define DEBUG_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define NL "\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef COLOR
 | 
				
			||||||
 | 
					#define KNRM "\033[0m"
 | 
				
			||||||
 | 
					#define KRED "\033[1;31m"
 | 
				
			||||||
 | 
					#define KGRN "\033[1;32m"
 | 
				
			||||||
 | 
					#define KYEL "\033[1;33m"
 | 
				
			||||||
 | 
					#define KBLU "\033[1;34m"
 | 
				
			||||||
 | 
					#define KMAG "\033[1;35m"
 | 
				
			||||||
 | 
					#define KCYN "\033[1;36m"
 | 
				
			||||||
 | 
					#define KWHT "\033[1;37m"
 | 
				
			||||||
 | 
					#define KBWN "\033[0;33m"
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#define KNRM ""
 | 
				
			||||||
 | 
					#define KRED ""
 | 
				
			||||||
 | 
					#define KGRN ""
 | 
				
			||||||
 | 
					#define KYEL ""
 | 
				
			||||||
 | 
					#define KBLU ""
 | 
				
			||||||
 | 
					#define KMAG ""
 | 
				
			||||||
 | 
					#define KCYN ""
 | 
				
			||||||
 | 
					#define KWHT ""
 | 
				
			||||||
 | 
					#define KBWN ""
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef VERBOSE
 | 
				
			||||||
 | 
					#define DEBUG
 | 
				
			||||||
 | 
					#define INFO
 | 
				
			||||||
 | 
					#define WARN
 | 
				
			||||||
 | 
					#define ERROR
 | 
				
			||||||
 | 
					#define SUCCESS
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef DEBUG
 | 
				
			||||||
 | 
					#define debug(S, ...)                                                          \
 | 
				
			||||||
 | 
					  do {                                                                         \
 | 
				
			||||||
 | 
					    fprintf(stderr, KMAG "DEBUG: %s:%s:%d " KNRM S NL, __FILE__,               \
 | 
				
			||||||
 | 
					            __extension__ __FUNCTION__, __LINE__, ##__VA_ARGS__);                \
 | 
				
			||||||
 | 
					  } while (0)
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#define debug(S, ...)
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef INFO
 | 
				
			||||||
 | 
					#define info(S, ...)                                                           \
 | 
				
			||||||
 | 
					  do {                                                                         \
 | 
				
			||||||
 | 
					    fprintf(stderr, KBLU "INFO: %s:%s:%d " KNRM S NL, __FILE__,                \
 | 
				
			||||||
 | 
					            __extension__ __FUNCTION__, __LINE__, ##__VA_ARGS__);                \
 | 
				
			||||||
 | 
					  } while (0)
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#define info(S, ...)
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef WARN
 | 
				
			||||||
 | 
					#define warn(S, ...)                                                           \
 | 
				
			||||||
 | 
					  do {                                                                         \
 | 
				
			||||||
 | 
					    fprintf(stderr, KYEL "WARN: %s:%s:%d " KNRM S NL, __FILE__,                \
 | 
				
			||||||
 | 
					            __extension__ __FUNCTION__, __LINE__, ##__VA_ARGS__);                \
 | 
				
			||||||
 | 
					  } while (0)
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#define warn(S, ...)
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef SUCCESS
 | 
				
			||||||
 | 
					#define success(S, ...)                                                        \
 | 
				
			||||||
 | 
					  do {                                                                         \
 | 
				
			||||||
 | 
					    fprintf(stderr, KGRN "SUCCESS: %s:%s:%d " KNRM S NL, __FILE__,             \
 | 
				
			||||||
 | 
					            __extension__ __FUNCTION__, __LINE__, ##__VA_ARGS__);                \
 | 
				
			||||||
 | 
					  } while (0)
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#define success(S, ...)
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef ERROR
 | 
				
			||||||
 | 
					#define error(S, ...)                                                          \
 | 
				
			||||||
 | 
					  do {                                                                         \
 | 
				
			||||||
 | 
					    fprintf(stderr, KRED "ERROR: %s:%s:%d " KNRM S NL, __FILE__,               \
 | 
				
			||||||
 | 
					            __extension__ __FUNCTION__, __LINE__, ##__VA_ARGS__);                \
 | 
				
			||||||
 | 
					  } while (0)
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#define error(S, ...)
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* DEBUG_H */
 | 
				
			||||||
							
								
								
									
										53
									
								
								hw4/include/mush.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								hw4/include/mush.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,53 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * DO NOT MODIFY THE CONTENTS OF THIS FILE.
 | 
				
			||||||
 | 
					 * IT WILL BE REPLACED DURING GRADING
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "syntax.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Names of special store variables to hold results from job execution. */
 | 
				
			||||||
 | 
					#define JOB_VAR "JOB"
 | 
				
			||||||
 | 
					#define STATUS_VAR "STATUS"
 | 
				
			||||||
 | 
					#define OUTPUT_VAR "OUTPUT"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * If you find it convenient, you may assume that the maximum number of jobs
 | 
				
			||||||
 | 
					 * that can exist at one time is given by the following preprocessor symbol.
 | 
				
			||||||
 | 
					 * Your code should continue to work even if the particular value of this
 | 
				
			||||||
 | 
					 * symbol is changed before compilation.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define MAX_JOBS 10
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Functions in program store module. */
 | 
				
			||||||
 | 
					int prog_list(FILE *out);
 | 
				
			||||||
 | 
					int prog_insert(STMT *stmt);
 | 
				
			||||||
 | 
					int prog_delete(int min, int max);
 | 
				
			||||||
 | 
					void prog_reset();
 | 
				
			||||||
 | 
					STMT *prog_fetch();
 | 
				
			||||||
 | 
					STMT *prog_next();
 | 
				
			||||||
 | 
					STMT *prog_goto(int lineno);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Functions in data store module. */
 | 
				
			||||||
 | 
					char *store_get_string(char *var);
 | 
				
			||||||
 | 
					int store_get_int(char *var, long *valp);
 | 
				
			||||||
 | 
					int store_set_string(char *var, char *val);
 | 
				
			||||||
 | 
					int store_set_int(char *var, long val);
 | 
				
			||||||
 | 
					void store_show(FILE *f);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Functions in execution module. */
 | 
				
			||||||
 | 
					int exec_interactive();
 | 
				
			||||||
 | 
					int exec_stmt(STMT *stmt);
 | 
				
			||||||
 | 
					char *eval_to_string(EXPR *expr);
 | 
				
			||||||
 | 
					long eval_to_numeric(EXPR *expr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Functions in jobs module. */
 | 
				
			||||||
 | 
					int jobs_init(void);
 | 
				
			||||||
 | 
					int jobs_fini(void);
 | 
				
			||||||
 | 
					int jobs_run(PIPELINE *pp);
 | 
				
			||||||
 | 
					int jobs_expunge(int jobid);
 | 
				
			||||||
 | 
					int jobs_wait(int jobid);
 | 
				
			||||||
 | 
					int jobs_poll(int jobid);
 | 
				
			||||||
 | 
					int jobs_cancel(int jobid);
 | 
				
			||||||
 | 
					int jobs_pause(void);
 | 
				
			||||||
 | 
					char *jobs_get_output(int jobid);
 | 
				
			||||||
 | 
					int jobs_show(FILE *file);
 | 
				
			||||||
							
								
								
									
										125
									
								
								hw4/include/mush.tab.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								hw4/include/mush.tab.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,125 @@
 | 
				
			||||||
 | 
					/* A Bison parser, made by GNU Bison 3.5.1.  */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Bison interface for Yacc-like parsers in C
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2020 Free Software Foundation,
 | 
				
			||||||
 | 
					   Inc.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   This program is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
					   it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					   the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
					   (at your option) any later version.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   This program is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					   but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					   GNU General Public License for more details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* As a special exception, you may create a larger work that contains
 | 
				
			||||||
 | 
					   part or all of the Bison parser skeleton and distribute that work
 | 
				
			||||||
 | 
					   under terms of your choice, so long as that work isn't itself a
 | 
				
			||||||
 | 
					   parser generator using the skeleton or a modified version thereof
 | 
				
			||||||
 | 
					   as a parser skeleton.  Alternatively, if you modify or redistribute
 | 
				
			||||||
 | 
					   the parser skeleton itself, you may (at your option) remove this
 | 
				
			||||||
 | 
					   special exception, which will cause the skeleton and the resulting
 | 
				
			||||||
 | 
					   Bison output files to be licensed under the GNU General Public
 | 
				
			||||||
 | 
					   License without this special exception.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   This special exception was added by the Free Software Foundation in
 | 
				
			||||||
 | 
					   version 2.2 of Bison.  */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Undocumented macros, especially those whose name start with YY_,
 | 
				
			||||||
 | 
					   are private implementation details.  Do not rely on them.  */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef YY_YY_INCLUDE_MUSH_TAB_H_INCLUDED
 | 
				
			||||||
 | 
					# define YY_YY_INCLUDE_MUSH_TAB_H_INCLUDED
 | 
				
			||||||
 | 
					/* Debug traces.  */
 | 
				
			||||||
 | 
					#ifndef YYDEBUG
 | 
				
			||||||
 | 
					# define YYDEBUG 1
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#if YYDEBUG
 | 
				
			||||||
 | 
					extern int yydebug;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Token type.  */
 | 
				
			||||||
 | 
					#ifndef YYTOKENTYPE
 | 
				
			||||||
 | 
					# define YYTOKENTYPE
 | 
				
			||||||
 | 
					  enum yytokentype
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    NUMBER = 258,
 | 
				
			||||||
 | 
					    NAME = 259,
 | 
				
			||||||
 | 
					    WORD = 260,
 | 
				
			||||||
 | 
					    STRING = 261,
 | 
				
			||||||
 | 
					    LIST = 262,
 | 
				
			||||||
 | 
					    DELETE = 263,
 | 
				
			||||||
 | 
					    RUN = 264,
 | 
				
			||||||
 | 
					    CONT = 265,
 | 
				
			||||||
 | 
					    STOP = 266,
 | 
				
			||||||
 | 
					    BG = 267,
 | 
				
			||||||
 | 
					    CAPTURE = 268,
 | 
				
			||||||
 | 
					    WAIT = 269,
 | 
				
			||||||
 | 
					    POLL = 270,
 | 
				
			||||||
 | 
					    CANCEL = 271,
 | 
				
			||||||
 | 
					    PAUSE = 272,
 | 
				
			||||||
 | 
					    SET = 273,
 | 
				
			||||||
 | 
					    UNSET = 274,
 | 
				
			||||||
 | 
					    IF = 275,
 | 
				
			||||||
 | 
					    GOTO = 276,
 | 
				
			||||||
 | 
					    SOURCE = 277,
 | 
				
			||||||
 | 
					    EQ = 278,
 | 
				
			||||||
 | 
					    PIPE = 279,
 | 
				
			||||||
 | 
					    LESS = 280,
 | 
				
			||||||
 | 
					    GREATER = 281,
 | 
				
			||||||
 | 
					    EQUAL = 282,
 | 
				
			||||||
 | 
					    LESSEQ = 283,
 | 
				
			||||||
 | 
					    GREATEQ = 284,
 | 
				
			||||||
 | 
					    AND = 285,
 | 
				
			||||||
 | 
					    OR = 286,
 | 
				
			||||||
 | 
					    NOT = 287,
 | 
				
			||||||
 | 
					    LPAREN = 288,
 | 
				
			||||||
 | 
					    RPAREN = 289,
 | 
				
			||||||
 | 
					    PLUS = 290,
 | 
				
			||||||
 | 
					    MINUS = 291,
 | 
				
			||||||
 | 
					    TIMES = 292,
 | 
				
			||||||
 | 
					    DIVIDE = 293,
 | 
				
			||||||
 | 
					    MOD = 294,
 | 
				
			||||||
 | 
					    COMMA = 295,
 | 
				
			||||||
 | 
					    SHARP = 296,
 | 
				
			||||||
 | 
					    DOLLAR = 297,
 | 
				
			||||||
 | 
					    EOL = 298,
 | 
				
			||||||
 | 
					    EoF = 299,
 | 
				
			||||||
 | 
					    UNKNOWN = 300
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Value type.  */
 | 
				
			||||||
 | 
					#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
 | 
				
			||||||
 | 
					union YYSTYPE
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					#line 30 "src/mush.y"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int number;
 | 
				
			||||||
 | 
					    char *string;
 | 
				
			||||||
 | 
					    STMT *stmt;
 | 
				
			||||||
 | 
					    EXPR *expr;	
 | 
				
			||||||
 | 
					    ARG *args;
 | 
				
			||||||
 | 
					    COMMAND *cmds;
 | 
				
			||||||
 | 
					    PIPELINE *pline;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#line 113 "include/mush.tab.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					typedef union YYSTYPE YYSTYPE;
 | 
				
			||||||
 | 
					# define YYSTYPE_IS_TRIVIAL 1
 | 
				
			||||||
 | 
					# define YYSTYPE_IS_DECLARED 1
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern YYSTYPE yylval;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int yyparse (void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* !YY_YY_INCLUDE_MUSH_TAB_H_INCLUDED  */
 | 
				
			||||||
							
								
								
									
										212
									
								
								hw4/include/syntax.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										212
									
								
								hw4/include/syntax.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,212 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * DO NOT MODIFY THE CONTENTS OF THIS FILE.
 | 
				
			||||||
 | 
					 * IT WILL BE REPLACED DURING GRADING
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * The elements of this enumerated type are used in the "class" field
 | 
				
			||||||
 | 
					 * of the "STMT" structure to specify the particular kind of statement
 | 
				
			||||||
 | 
					 * that the structure represents.  The parenthesized names in the comments
 | 
				
			||||||
 | 
					 * indicate which element (if any) of the "members" union in the STMT
 | 
				
			||||||
 | 
					 * structure is used by each kind of statement.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					typedef enum {
 | 
				
			||||||
 | 
					    NO_STMT_CLASS,
 | 
				
			||||||
 | 
					    LIST_STMT_CLASS,            // "list" statement
 | 
				
			||||||
 | 
					    DELETE_STMT_CLASS,          // "delete" statement (delete_stmt)
 | 
				
			||||||
 | 
					    RUN_STMT_CLASS,             // "run" statement
 | 
				
			||||||
 | 
					    CONT_STMT_CLASS,            // "cont" statement
 | 
				
			||||||
 | 
					    STOP_STMT_CLASS,            // "stop" statement
 | 
				
			||||||
 | 
					    WAIT_STMT_CLASS,            // "wait" statement (jobctl_stmt)
 | 
				
			||||||
 | 
					    POLL_STMT_CLASS,            // "poll" statement (jobctl_stmt)
 | 
				
			||||||
 | 
					    CANCEL_STMT_CLASS,          // "cancel" statement (jobctl_stmt)
 | 
				
			||||||
 | 
					    PAUSE_STMT_CLASS,           // "pause" statement
 | 
				
			||||||
 | 
					    SET_STMT_CLASS,             // "set" statement (set_stmt)
 | 
				
			||||||
 | 
					    UNSET_STMT_CLASS,           // "unset" statement (unset_stmt)
 | 
				
			||||||
 | 
					    IF_STMT_CLASS,              // "if" statement (if_stmt)
 | 
				
			||||||
 | 
					    GOTO_STMT_CLASS,            // "goto" statement (goto_stmt)
 | 
				
			||||||
 | 
					    SOURCE_STMT_CLASS,          // "source" statement (source_stmt)
 | 
				
			||||||
 | 
					    FG_STMT_CLASS,              // pipeline run in foreground (sys_stmt)
 | 
				
			||||||
 | 
					    BG_STMT_CLASS               // pipeline run in background (sys_stmt)
 | 
				
			||||||
 | 
					} STMT_CLASS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * This structure is used to represent a statement.
 | 
				
			||||||
 | 
					 * The value in the "class" field tells what kind of statement it is.
 | 
				
			||||||
 | 
					 * Depending on this value, one of the fields of the "members" union
 | 
				
			||||||
 | 
					 * may be valid.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					typedef struct stmt {
 | 
				
			||||||
 | 
					    STMT_CLASS class;
 | 
				
			||||||
 | 
					    int lineno;
 | 
				
			||||||
 | 
					    union {
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
						    int from;
 | 
				
			||||||
 | 
						    int to;
 | 
				
			||||||
 | 
						} delete_stmt;
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
						    struct pipeline *pipeline;
 | 
				
			||||||
 | 
						} sys_stmt;
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
						    struct expr *expr;
 | 
				
			||||||
 | 
						} jobctl_stmt;
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
						    char *name;
 | 
				
			||||||
 | 
						    struct expr *expr;
 | 
				
			||||||
 | 
						} set_stmt;
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
						    char *name;
 | 
				
			||||||
 | 
						} unset_stmt;
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
						    struct expr *expr;
 | 
				
			||||||
 | 
						    int lineno;
 | 
				
			||||||
 | 
						} if_stmt;
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
						    int lineno;
 | 
				
			||||||
 | 
						} goto_stmt;
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
						    char *file;
 | 
				
			||||||
 | 
						} source_stmt;
 | 
				
			||||||
 | 
					    } members;
 | 
				
			||||||
 | 
					} STMT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * This structure is used to represent a command.  The "args" field points
 | 
				
			||||||
 | 
					 * to the head of as a nonempty linked list of "args" that make up the command.
 | 
				
			||||||
 | 
					 * The first "arg" is interpreted as the name of the command; the remainder
 | 
				
			||||||
 | 
					 * are arguments to it.  The "next" field is used to link commands into a
 | 
				
			||||||
 | 
					 * pipeline.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					typedef struct command {
 | 
				
			||||||
 | 
					    struct arg *args;
 | 
				
			||||||
 | 
					    struct command *next;
 | 
				
			||||||
 | 
					} COMMAND;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * This structure is used to represent a "pipeline".  The "commands" field
 | 
				
			||||||
 | 
					 * points to the head of a nonempty list of commands.  The "input_file" field,
 | 
				
			||||||
 | 
					 * if non-NULL, is the name of a file from which input to the first command
 | 
				
			||||||
 | 
					 * in the pipeline is to be redirected.  Similarly, the "output_file" field,
 | 
				
			||||||
 | 
					 * if non-NULL, is the name of a file to which output from the last command
 | 
				
			||||||
 | 
					 * in the pipeline is to be redirected.  If the "capture_output" field is
 | 
				
			||||||
 | 
					 * nonzero, then instead of being redirected to a file, the output from the
 | 
				
			||||||
 | 
					 * last command in the pipeline is to be redirected to a pipe.  This pipe is
 | 
				
			||||||
 | 
					 * to be read by the main process, which will "captures" the output and make
 | 
				
			||||||
 | 
					 * it available as the value of a variable in the data store.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					typedef struct pipeline {
 | 
				
			||||||
 | 
					    COMMAND *commands;
 | 
				
			||||||
 | 
					    char *input_file;
 | 
				
			||||||
 | 
					    char *output_file;
 | 
				
			||||||
 | 
					    int capture_output;
 | 
				
			||||||
 | 
					} PIPELINE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Values of this enumerated type are used to identify the various kinds
 | 
				
			||||||
 | 
					 * of expressions.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					typedef enum {
 | 
				
			||||||
 | 
					    NO_EXPR_CLASS,
 | 
				
			||||||
 | 
					    LIT_EXPR_CLASS,             // literal string (value)
 | 
				
			||||||
 | 
					    NUM_EXPR_CLASS,             // numeric variable (variable)
 | 
				
			||||||
 | 
					    STRING_EXPR_CLASS,          // string variable (variable)
 | 
				
			||||||
 | 
					    UNARY_EXPR_CLASS,           // unary expression (unary_expr)
 | 
				
			||||||
 | 
					    BINARY_EXPR_CLASS           // binary expression (binary_expr)
 | 
				
			||||||
 | 
					} EXPR_CLASS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Values of this enumerated type are used to identify the various kinds
 | 
				
			||||||
 | 
					 * of operators in expressions.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					typedef enum {
 | 
				
			||||||
 | 
					    NO_OPRTR,
 | 
				
			||||||
 | 
					    NOT_OPRTR,                  // "not" operator (unary_expr)
 | 
				
			||||||
 | 
					    AND_OPRTR,                  // "and" operator (binary_expr)
 | 
				
			||||||
 | 
					    OR_OPRTR,                   // "or" operator (binary_expr)
 | 
				
			||||||
 | 
					    EQUAL_OPRTR,                // "equal to" operator (binary_expr)
 | 
				
			||||||
 | 
					    LESS_OPRTR,                 // "less than" operator (binary_expr)
 | 
				
			||||||
 | 
					    GREATER_OPRTR,              // "greater than" operator (binary_expr)
 | 
				
			||||||
 | 
					    LESSEQ_OPRTR,               // "less than or equal" operator (binary_expr)
 | 
				
			||||||
 | 
					    GREATEQ_OPRTR,              // "greater than or equal" operator (binary_expr)
 | 
				
			||||||
 | 
					    PLUS_OPRTR,                 // "plus" (binary_expr)
 | 
				
			||||||
 | 
					    MINUS_OPRTR,                // "minus" (binary_expr)
 | 
				
			||||||
 | 
					    TIMES_OPRTR,                // "times" (binary_expr)
 | 
				
			||||||
 | 
					    DIVIDE_OPRTR,               // "divide" (binary_expr)
 | 
				
			||||||
 | 
					    MOD_OPRTR                   // "mod" (binary_expr)
 | 
				
			||||||
 | 
					} OPRTR;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Values of this enumerated type are used to identify the various kinds
 | 
				
			||||||
 | 
					 * values that an expression can have.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					typedef enum {
 | 
				
			||||||
 | 
					    NO_VALUE_TYPE,
 | 
				
			||||||
 | 
					    NUM_VALUE_TYPE,              // numeric value
 | 
				
			||||||
 | 
					    STRING_VALUE_TYPE            // string value
 | 
				
			||||||
 | 
					} VALUE_TYPE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * This structure is used to represent an "expression".
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					typedef struct expr {
 | 
				
			||||||
 | 
					    EXPR_CLASS class;
 | 
				
			||||||
 | 
					    VALUE_TYPE type;
 | 
				
			||||||
 | 
					    union {
 | 
				
			||||||
 | 
						char *variable;
 | 
				
			||||||
 | 
						char *value;
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
						    OPRTR oprtr;
 | 
				
			||||||
 | 
						    struct expr *arg;
 | 
				
			||||||
 | 
						} unary_expr;
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
						    OPRTR oprtr;
 | 
				
			||||||
 | 
						    struct expr *arg1;
 | 
				
			||||||
 | 
						    struct expr *arg2;
 | 
				
			||||||
 | 
						} binary_expr;
 | 
				
			||||||
 | 
					    } members;
 | 
				
			||||||
 | 
					} EXPR;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * This structure is used to represent an "argument", which is
 | 
				
			||||||
 | 
					 * a single element of a command.  Arguments contain arbitrary expressions,
 | 
				
			||||||
 | 
					 * which allows commands to be constructed that depend on the values
 | 
				
			||||||
 | 
					 * of variables.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					typedef struct arg {
 | 
				
			||||||
 | 
					    EXPR *expr;
 | 
				
			||||||
 | 
					    struct arg *next;
 | 
				
			||||||
 | 
					} ARG;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * The following functions are used to print representations
 | 
				
			||||||
 | 
					 * of the various syntactic objects to a specified output stream.
 | 
				
			||||||
 | 
					 * A nonzero value for the "parens" argument of show_expr() causes
 | 
				
			||||||
 | 
					 * a compound expression to be printed within enclosing parentheses.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void show_stmt(FILE *file, STMT *stmt);
 | 
				
			||||||
 | 
					void show_pipeline(FILE *file, PIPELINE *pline);
 | 
				
			||||||
 | 
					void show_command(FILE *file, COMMAND *cmd);
 | 
				
			||||||
 | 
					void show_expr(FILE *file, EXPR *expr, int parens);
 | 
				
			||||||
 | 
					void show_oprtr(FILE *file, OPRTR oprtr);
 | 
				
			||||||
 | 
					void show_lineno(FILE *file, int lineno);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * The following functions are use to free the various syntactic
 | 
				
			||||||
 | 
					 * objects.  Freeing an object with one of these functions implies
 | 
				
			||||||
 | 
					 * freeing all the objects that it references.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void free_stmt(STMT *stmt);
 | 
				
			||||||
 | 
					void free_pipeline(PIPELINE *pline);
 | 
				
			||||||
 | 
					void free_commands(COMMAND *cmd);
 | 
				
			||||||
 | 
					void free_args(ARG *args);
 | 
				
			||||||
 | 
					void free_expr(EXPR *expr);
 | 
				
			||||||
 | 
					void free_oprtr(OPRTR oprtr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * The following functions are use to make deep copies of the
 | 
				
			||||||
 | 
					 * various syntactic objects.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					PIPELINE *copy_pipeline(PIPELINE *pline);
 | 
				
			||||||
 | 
					COMMAND *copy_commands(COMMAND *cmd);
 | 
				
			||||||
 | 
					ARG *copy_args(ARG *args);
 | 
				
			||||||
 | 
					EXPR *copy_expr(EXPR *expr);
 | 
				
			||||||
							
								
								
									
										7
									
								
								hw4/rsrc/bg_test.mush
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								hw4/rsrc/bg_test.mush
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,7 @@
 | 
				
			||||||
 | 
					10 sleep 10 &
 | 
				
			||||||
 | 
					15 echo line 15
 | 
				
			||||||
 | 
					20 sleep 5 &
 | 
				
			||||||
 | 
					25 echo line 25
 | 
				
			||||||
 | 
					30 sleep 3 &
 | 
				
			||||||
 | 
					35 echo line 35
 | 
				
			||||||
 | 
					run
 | 
				
			||||||
							
								
								
									
										6
									
								
								hw4/rsrc/cancel_test.mush
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								hw4/rsrc/cancel_test.mush
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,6 @@
 | 
				
			||||||
 | 
					10 sleep 10 &
 | 
				
			||||||
 | 
					15 set j10 = #JOB
 | 
				
			||||||
 | 
					20 sleep 2
 | 
				
			||||||
 | 
					30 cancel #j10
 | 
				
			||||||
 | 
					40 wait #j10
 | 
				
			||||||
 | 
					run
 | 
				
			||||||
							
								
								
									
										7
									
								
								hw4/rsrc/delete_test.mush
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								hw4/rsrc/delete_test.mush
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,7 @@
 | 
				
			||||||
 | 
					10 echo line 10
 | 
				
			||||||
 | 
					20 echo line 20
 | 
				
			||||||
 | 
					30 echo line 30
 | 
				
			||||||
 | 
					40 echo line 40
 | 
				
			||||||
 | 
					50 echo line 50
 | 
				
			||||||
 | 
					delete 10,25
 | 
				
			||||||
 | 
					list
 | 
				
			||||||
							
								
								
									
										7
									
								
								hw4/rsrc/fg_test.mush
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								hw4/rsrc/fg_test.mush
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,7 @@
 | 
				
			||||||
 | 
					10 sleep 10
 | 
				
			||||||
 | 
					15 echo line 15
 | 
				
			||||||
 | 
					20 sleep 5
 | 
				
			||||||
 | 
					25 echo line 25
 | 
				
			||||||
 | 
					30 sleep 3
 | 
				
			||||||
 | 
					35 echo line 35
 | 
				
			||||||
 | 
					run
 | 
				
			||||||
							
								
								
									
										4
									
								
								hw4/rsrc/goto_test.mush
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								hw4/rsrc/goto_test.mush
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,4 @@
 | 
				
			||||||
 | 
					10 goto 30
 | 
				
			||||||
 | 
					20 stop
 | 
				
			||||||
 | 
					30 echo yes
 | 
				
			||||||
 | 
					run
 | 
				
			||||||
							
								
								
									
										3
									
								
								hw4/rsrc/list_test.mush
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								hw4/rsrc/list_test.mush
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,3 @@
 | 
				
			||||||
 | 
					10 echo line 10
 | 
				
			||||||
 | 
					20 echo line 20
 | 
				
			||||||
 | 
					list
 | 
				
			||||||
							
								
								
									
										4
									
								
								hw4/rsrc/loop1.mush
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								hw4/rsrc/loop1.mush
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,4 @@
 | 
				
			||||||
 | 
					10 echo hello 
 | 
				
			||||||
 | 
					20 sleep 1
 | 
				
			||||||
 | 
					30 goto 10
 | 
				
			||||||
 | 
					run
 | 
				
			||||||
							
								
								
									
										8
									
								
								hw4/rsrc/loop2.mush
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								hw4/rsrc/loop2.mush
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,8 @@
 | 
				
			||||||
 | 
					10 set x = 1
 | 
				
			||||||
 | 
					20 echo #x
 | 
				
			||||||
 | 
					25 sleep 1
 | 
				
			||||||
 | 
					30 set x = !#x
 | 
				
			||||||
 | 
					35 echo #x
 | 
				
			||||||
 | 
					40 sleep 1
 | 
				
			||||||
 | 
					50 goto 10
 | 
				
			||||||
 | 
					run
 | 
				
			||||||
							
								
								
									
										3
									
								
								hw4/rsrc/pause_test.mush
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								hw4/rsrc/pause_test.mush
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,3 @@
 | 
				
			||||||
 | 
					10 sleep 10 &
 | 
				
			||||||
 | 
					20 pause
 | 
				
			||||||
 | 
					run
 | 
				
			||||||
							
								
								
									
										3
									
								
								hw4/rsrc/pipeline_test.mush
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								hw4/rsrc/pipeline_test.mush
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,3 @@
 | 
				
			||||||
 | 
					10 cat "/usr/share/dict/words" | grep program | grep sub > "pipeline_test.out"
 | 
				
			||||||
 | 
					20 cat "pipeline_test.out"
 | 
				
			||||||
 | 
					run
 | 
				
			||||||
							
								
								
									
										4
									
								
								hw4/rsrc/run_test.mush
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								hw4/rsrc/run_test.mush
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,4 @@
 | 
				
			||||||
 | 
					10 echo line 10
 | 
				
			||||||
 | 
					20 echo line 20
 | 
				
			||||||
 | 
					30 echo line 30
 | 
				
			||||||
 | 
					run
 | 
				
			||||||
							
								
								
									
										4
									
								
								hw4/rsrc/stop_test.mush
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								hw4/rsrc/stop_test.mush
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,4 @@
 | 
				
			||||||
 | 
					10 echo line 10
 | 
				
			||||||
 | 
					20 stop
 | 
				
			||||||
 | 
					30 echo line 30
 | 
				
			||||||
 | 
					run
 | 
				
			||||||
							
								
								
									
										19
									
								
								hw4/rsrc/wait_test.mush
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								hw4/rsrc/wait_test.mush
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,19 @@
 | 
				
			||||||
 | 
					10 sleep 10 &
 | 
				
			||||||
 | 
					11 set j10 = #JOB
 | 
				
			||||||
 | 
					12 echo j10 #j10
 | 
				
			||||||
 | 
					15 echo line 15
 | 
				
			||||||
 | 
					20 sleep 5 &
 | 
				
			||||||
 | 
					21 set j20 = #JOB
 | 
				
			||||||
 | 
					22 echo j20 #j20
 | 
				
			||||||
 | 
					25 echo line 25
 | 
				
			||||||
 | 
					30 sleep 3 &
 | 
				
			||||||
 | 
					31 set j30 = #JOB
 | 
				
			||||||
 | 
					32 echo j30 #j30
 | 
				
			||||||
 | 
					35 echo line 35
 | 
				
			||||||
 | 
					40 wait #j30
 | 
				
			||||||
 | 
					45 echo j30 #STATUS
 | 
				
			||||||
 | 
					50 wait #j20
 | 
				
			||||||
 | 
					55 echo j20 #STATUS
 | 
				
			||||||
 | 
					60 wait #j10
 | 
				
			||||||
 | 
					65 echo j10 #STATUS
 | 
				
			||||||
 | 
					run
 | 
				
			||||||
							
								
								
									
										400
									
								
								hw4/src/execution.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										400
									
								
								hw4/src/execution.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,400 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * DO NOT MODIFY THE CONTENTS OF THIS FILE.
 | 
				
			||||||
 | 
					 * IT WILL BE REPLACED DURING GRADING
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <setjmp.h>
 | 
				
			||||||
 | 
					#include <signal.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "mush.h"
 | 
				
			||||||
 | 
					#include "mush.tab.h"
 | 
				
			||||||
 | 
					#include "debug.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Mush: Execution engine.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern int yylex_destroy();
 | 
				
			||||||
 | 
					extern void push_input(FILE *in);
 | 
				
			||||||
 | 
					extern int pop_input(void);
 | 
				
			||||||
 | 
					extern int input_depth(void);
 | 
				
			||||||
 | 
					extern STMT *mush_parsed_stmt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int exec_run();
 | 
				
			||||||
 | 
					static int exec_cont();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define PROMPT "mush: "
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Uncomment this to enable tracing of the parser. */
 | 
				
			||||||
 | 
					//int yydebug = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * A quit handler is installed to allow user-initiated escape
 | 
				
			||||||
 | 
					 * from constructs that wait for signals.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static volatile sig_atomic_t got_quit = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void handler(int sig) {
 | 
				
			||||||
 | 
					    got_quit = 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Target for longjmp() to jump to after a low-level error has
 | 
				
			||||||
 | 
					 * occurred, e.g. in expression evaluation.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static jmp_buf onerror;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Top-level interpreter loop.
 | 
				
			||||||
 | 
					 * Reads single statements from stdin and either inserts them into the program,
 | 
				
			||||||
 | 
					 * if they have a line number, otherwise executes them immediately.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int exec_interactive() {
 | 
				
			||||||
 | 
					    signal(SIGQUIT, SIG_IGN);
 | 
				
			||||||
 | 
					    while(1) {
 | 
				
			||||||
 | 
						if(!input_depth() && isatty(fileno(stdin)))
 | 
				
			||||||
 | 
						    fprintf(stdout, "%s", PROMPT);
 | 
				
			||||||
 | 
						fflush(stdout);
 | 
				
			||||||
 | 
						if(!yyparse()) {
 | 
				
			||||||
 | 
						    STMT *stmt = mush_parsed_stmt;
 | 
				
			||||||
 | 
						    if(stmt != NULL) {
 | 
				
			||||||
 | 
							if(stmt->lineno) {
 | 
				
			||||||
 | 
							    prog_insert(stmt);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
							    if(stmt->class == RUN_STMT_CLASS) {
 | 
				
			||||||
 | 
								free_stmt(stmt);
 | 
				
			||||||
 | 
								stmt = NULL;
 | 
				
			||||||
 | 
								exec_run();
 | 
				
			||||||
 | 
							    } else if(stmt->class == CONT_STMT_CLASS) {
 | 
				
			||||||
 | 
								free_stmt(stmt);
 | 
				
			||||||
 | 
								stmt = NULL;
 | 
				
			||||||
 | 
								exec_cont();
 | 
				
			||||||
 | 
							    } else {
 | 
				
			||||||
 | 
								exec_stmt(stmt);
 | 
				
			||||||
 | 
								free_stmt(stmt);
 | 
				
			||||||
 | 
								stmt = NULL;
 | 
				
			||||||
 | 
							    }
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						    }
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
						    if(pop_input())
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if(!input_depth() && isatty(fileno(stdin))) {
 | 
				
			||||||
 | 
						    store_show(stderr);
 | 
				
			||||||
 | 
						    fprintf(stderr, "\n");
 | 
				
			||||||
 | 
						    jobs_show(stderr);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    yylex_destroy();
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Enter an execution loop starting at the beginning of the program.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int exec_run() {
 | 
				
			||||||
 | 
					    prog_reset();
 | 
				
			||||||
 | 
					    return exec_cont();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Enter an execution loop starting at the current line number.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int exec_cont() {
 | 
				
			||||||
 | 
					    int err = 0;
 | 
				
			||||||
 | 
					    STMT *stmt;
 | 
				
			||||||
 | 
					    stmt = prog_fetch();
 | 
				
			||||||
 | 
					    if(stmt == NULL) {
 | 
				
			||||||
 | 
						fprintf(stderr, "No statement to execute\n");
 | 
				
			||||||
 | 
						return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if(setjmp(onerror))
 | 
				
			||||||
 | 
						return -1;
 | 
				
			||||||
 | 
					    signal(SIGQUIT, handler);
 | 
				
			||||||
 | 
					    while(!got_quit) {
 | 
				
			||||||
 | 
						stmt = prog_fetch();
 | 
				
			||||||
 | 
						if(!stmt) {
 | 
				
			||||||
 | 
						    fprintf(stderr, "STOP (end of program)\n");
 | 
				
			||||||
 | 
						    break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						prog_next();
 | 
				
			||||||
 | 
						err = exec_stmt(stmt);
 | 
				
			||||||
 | 
						if(err)
 | 
				
			||||||
 | 
						    break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    signal(SIGQUIT, SIG_IGN);
 | 
				
			||||||
 | 
					    if(got_quit)
 | 
				
			||||||
 | 
						fprintf(stderr, "Quit!\n");
 | 
				
			||||||
 | 
					    got_quit = 0;
 | 
				
			||||||
 | 
					    return err;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Execute a statement.
 | 
				
			||||||
 | 
					 * This function is called from exec_run().
 | 
				
			||||||
 | 
					 * It can also be called separately to execute an individual statement
 | 
				
			||||||
 | 
					 * read interactively.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Successful execution (except for STOP) returns 0.
 | 
				
			||||||
 | 
					 * Successful execution of STOP returns 1.
 | 
				
			||||||
 | 
					 * Unsuccessful execution returns -1.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int exec_stmt(STMT *stmt) {
 | 
				
			||||||
 | 
					    int val; char *str;
 | 
				
			||||||
 | 
					    FILE *in;
 | 
				
			||||||
 | 
					    if(setjmp(onerror))
 | 
				
			||||||
 | 
						return -1;
 | 
				
			||||||
 | 
					    if(stmt->lineno)
 | 
				
			||||||
 | 
						debug("execute statement %d", stmt->lineno);
 | 
				
			||||||
 | 
					    switch(stmt->class) {
 | 
				
			||||||
 | 
					    case LIST_STMT_CLASS:
 | 
				
			||||||
 | 
						prog_list(stdout);
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case DELETE_STMT_CLASS:
 | 
				
			||||||
 | 
						prog_delete(stmt->members.delete_stmt.from, stmt->members.delete_stmt.to);
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case STOP_STMT_CLASS:
 | 
				
			||||||
 | 
						if(stmt->lineno)
 | 
				
			||||||
 | 
						    fprintf(stderr, "STOP at line %d\n", stmt->lineno);
 | 
				
			||||||
 | 
						return 1;
 | 
				
			||||||
 | 
					    case GOTO_STMT_CLASS:
 | 
				
			||||||
 | 
						if(!prog_goto(stmt->members.goto_stmt.lineno))
 | 
				
			||||||
 | 
						    return -1;
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case SET_STMT_CLASS:
 | 
				
			||||||
 | 
						switch(stmt->members.set_stmt.expr->type) {
 | 
				
			||||||
 | 
						case NUM_VALUE_TYPE:
 | 
				
			||||||
 | 
						    val = eval_to_numeric(stmt->members.set_stmt.expr);
 | 
				
			||||||
 | 
						    store_set_int(stmt->members.set_stmt.name, val);
 | 
				
			||||||
 | 
						    break;
 | 
				
			||||||
 | 
						case STRING_VALUE_TYPE:
 | 
				
			||||||
 | 
						    str = eval_to_string(stmt->members.set_stmt.expr);
 | 
				
			||||||
 | 
						    store_set_string(stmt->members.set_stmt.name, str);
 | 
				
			||||||
 | 
						    break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
						    break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case UNSET_STMT_CLASS:
 | 
				
			||||||
 | 
						store_set_string(stmt->members.unset_stmt.name, NULL);
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case IF_STMT_CLASS:
 | 
				
			||||||
 | 
						val = eval_to_numeric(stmt->members.if_stmt.expr);
 | 
				
			||||||
 | 
						if(val) {
 | 
				
			||||||
 | 
						    if(!prog_goto(stmt->members.if_stmt.lineno))
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						    else
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case SOURCE_STMT_CLASS:
 | 
				
			||||||
 | 
						in = fopen(stmt->members.source_stmt.file, "r");
 | 
				
			||||||
 | 
						if(!in) {
 | 
				
			||||||
 | 
						    fprintf(stderr, "Couldn't open source file: '%s'\n",
 | 
				
			||||||
 | 
							    stmt->members.source_stmt.file);
 | 
				
			||||||
 | 
						    return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						push_input(in);
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case FG_STMT_CLASS:
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
						    PIPELINE *pp = stmt->members.sys_stmt.pipeline;
 | 
				
			||||||
 | 
						    int job = jobs_run(pp);
 | 
				
			||||||
 | 
						    store_set_int(JOB_VAR, job);
 | 
				
			||||||
 | 
						    int status = jobs_wait(job);
 | 
				
			||||||
 | 
						    store_set_int(STATUS_VAR, status);
 | 
				
			||||||
 | 
						    if(pp->capture_output) {
 | 
				
			||||||
 | 
							char *output = jobs_get_output(job);
 | 
				
			||||||
 | 
							debug("Captured output: '%s'", output);
 | 
				
			||||||
 | 
							store_set_string(OUTPUT_VAR, output);
 | 
				
			||||||
 | 
						    }
 | 
				
			||||||
 | 
						    jobs_expunge(job);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case BG_STMT_CLASS:
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
						    int job = jobs_run(stmt->members.sys_stmt.pipeline);
 | 
				
			||||||
 | 
						    store_set_int(JOB_VAR, job);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case WAIT_STMT_CLASS:
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
						    int job = eval_to_numeric(stmt->members.jobctl_stmt.expr);
 | 
				
			||||||
 | 
						    int status = jobs_wait(job);
 | 
				
			||||||
 | 
						    store_set_int(STATUS_VAR, status);
 | 
				
			||||||
 | 
						    char *output = jobs_get_output(job);
 | 
				
			||||||
 | 
						    if(output)
 | 
				
			||||||
 | 
							store_set_string(OUTPUT_VAR, output);
 | 
				
			||||||
 | 
						    jobs_expunge(job);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case POLL_STMT_CLASS:
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
						    int job = eval_to_numeric(stmt->members.jobctl_stmt.expr);
 | 
				
			||||||
 | 
						    int status = jobs_poll(job);
 | 
				
			||||||
 | 
						    store_set_int(STATUS_VAR, status);
 | 
				
			||||||
 | 
						    if(status >= 0) {
 | 
				
			||||||
 | 
							char *output = jobs_get_output(job);
 | 
				
			||||||
 | 
							if(output)
 | 
				
			||||||
 | 
							    store_set_string(OUTPUT_VAR, output);
 | 
				
			||||||
 | 
							jobs_expunge(job);
 | 
				
			||||||
 | 
						    }
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case CANCEL_STMT_CLASS:
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
						    int job = eval_to_numeric(stmt->members.jobctl_stmt.expr);
 | 
				
			||||||
 | 
						    jobs_cancel(job);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case PAUSE_STMT_CLASS:
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
						    jobs_pause();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
						fprintf(stderr, "Unknown statement class: %d\n", stmt->class);
 | 
				
			||||||
 | 
						abort();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Evaluate an expression, returning an integer result.
 | 
				
			||||||
 | 
					 * It is assumed that the jmp_buf onerror has been initialized by the caller
 | 
				
			||||||
 | 
					 * with a control point to escape to in case there is an error during evaluation.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					long eval_to_numeric(EXPR *expr) {
 | 
				
			||||||
 | 
					    char *endp, *str1, *str2;
 | 
				
			||||||
 | 
					    long opr1, opr2;
 | 
				
			||||||
 | 
					    int err;
 | 
				
			||||||
 | 
					    switch(expr->class) {
 | 
				
			||||||
 | 
					    case LIT_EXPR_CLASS:
 | 
				
			||||||
 | 
						opr1 = strtol(expr->members.value, &endp, 0);
 | 
				
			||||||
 | 
						if(*endp == '\0') {
 | 
				
			||||||
 | 
						    return opr1;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
						    fprintf(stderr, "Literal '%s' is not an integer\n", expr->members.value);
 | 
				
			||||||
 | 
						    longjmp(onerror, 0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					    case STRING_EXPR_CLASS:
 | 
				
			||||||
 | 
					    case NUM_EXPR_CLASS:
 | 
				
			||||||
 | 
						err = store_get_int(expr->members.variable, &opr1);
 | 
				
			||||||
 | 
						if(err) {
 | 
				
			||||||
 | 
						    fprintf(stderr, "Variable %s does not have an integer value\n",
 | 
				
			||||||
 | 
							    expr->members.variable);
 | 
				
			||||||
 | 
						    longjmp(onerror, 0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return opr1;
 | 
				
			||||||
 | 
						fprintf(stderr, "String variable %s in expression not implemented\n",
 | 
				
			||||||
 | 
							expr->members.variable);
 | 
				
			||||||
 | 
						abort();
 | 
				
			||||||
 | 
					    case UNARY_EXPR_CLASS:
 | 
				
			||||||
 | 
						opr1 = eval_to_numeric(expr->members.unary_expr.arg);
 | 
				
			||||||
 | 
						switch(expr->members.unary_expr.oprtr) {
 | 
				
			||||||
 | 
						case NOT_OPRTR:
 | 
				
			||||||
 | 
						    return opr1 ? 0 : 1;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
						    fprintf(stderr, "Unknown unary numeric operator: %d\n",
 | 
				
			||||||
 | 
							    expr->members.unary_expr.oprtr);
 | 
				
			||||||
 | 
						    abort();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					    case BINARY_EXPR_CLASS:
 | 
				
			||||||
 | 
						if(expr->members.binary_expr.oprtr == EQUAL_OPRTR) {
 | 
				
			||||||
 | 
						    if(expr->members.binary_expr.arg1->type == NUM_VALUE_TYPE &&
 | 
				
			||||||
 | 
						       expr->members.binary_expr.arg2->type == NUM_VALUE_TYPE) {
 | 
				
			||||||
 | 
							opr1 = eval_to_numeric(expr->members.binary_expr.arg1);
 | 
				
			||||||
 | 
							opr2 = eval_to_numeric(expr->members.binary_expr.arg2);
 | 
				
			||||||
 | 
							return opr1 == opr2;
 | 
				
			||||||
 | 
						    } else {
 | 
				
			||||||
 | 
							str1 = eval_to_string(expr->members.binary_expr.arg1);
 | 
				
			||||||
 | 
							str2 = eval_to_string(expr->members.binary_expr.arg2);
 | 
				
			||||||
 | 
							return !strcmp(str1, str2);
 | 
				
			||||||
 | 
						    }
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						opr1 = eval_to_numeric(expr->members.binary_expr.arg1);
 | 
				
			||||||
 | 
						opr2 = eval_to_numeric(expr->members.binary_expr.arg2);
 | 
				
			||||||
 | 
						switch(expr->members.binary_expr.oprtr) {
 | 
				
			||||||
 | 
						case AND_OPRTR:
 | 
				
			||||||
 | 
						    return opr1 && opr2;
 | 
				
			||||||
 | 
						case OR_OPRTR:
 | 
				
			||||||
 | 
						    return opr1 || opr2;
 | 
				
			||||||
 | 
						case PLUS_OPRTR:
 | 
				
			||||||
 | 
						    return opr1 + opr2;
 | 
				
			||||||
 | 
						case MINUS_OPRTR:
 | 
				
			||||||
 | 
						    return opr1 - opr2;
 | 
				
			||||||
 | 
						case TIMES_OPRTR:
 | 
				
			||||||
 | 
						    return opr1 * opr2;
 | 
				
			||||||
 | 
						case DIVIDE_OPRTR:
 | 
				
			||||||
 | 
						    return opr1 / opr2;
 | 
				
			||||||
 | 
						case MOD_OPRTR:
 | 
				
			||||||
 | 
						    return opr1 % opr2;
 | 
				
			||||||
 | 
						case LESS_OPRTR:
 | 
				
			||||||
 | 
						    return opr1 < opr2;
 | 
				
			||||||
 | 
						case GREATER_OPRTR:
 | 
				
			||||||
 | 
						    return opr1 > opr2;
 | 
				
			||||||
 | 
						case LESSEQ_OPRTR:
 | 
				
			||||||
 | 
						    return opr1 <= opr2;
 | 
				
			||||||
 | 
						case GREATEQ_OPRTR:
 | 
				
			||||||
 | 
						    return opr1 >= opr2;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
						    fprintf(stderr, "Unknown binary numeric operator: %d\n",
 | 
				
			||||||
 | 
							    expr->members.binary_expr.oprtr);
 | 
				
			||||||
 | 
						    abort();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
						fprintf(stderr, "Unknown expression class: %d\n", expr->class);
 | 
				
			||||||
 | 
						abort();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Evaluate an expression, returning a string result.
 | 
				
			||||||
 | 
					 * It is assumed that the jmp_buf onerror has been initialized by the caller
 | 
				
			||||||
 | 
					 * with a control point to escape to in case there is an error during evaluation.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					char *eval_to_string(EXPR *expr) {
 | 
				
			||||||
 | 
					    char *str1, *str2;
 | 
				
			||||||
 | 
					    switch(expr->class) {
 | 
				
			||||||
 | 
					    case LIT_EXPR_CLASS:
 | 
				
			||||||
 | 
						return expr->members.value;
 | 
				
			||||||
 | 
					    case NUM_EXPR_CLASS:
 | 
				
			||||||
 | 
					    case STRING_EXPR_CLASS:
 | 
				
			||||||
 | 
						str1 = store_get_string(expr->members.variable);
 | 
				
			||||||
 | 
						if(!str1) {
 | 
				
			||||||
 | 
						    fprintf(stderr, "Variable %s does not have a value\n",
 | 
				
			||||||
 | 
							    expr->members.variable);
 | 
				
			||||||
 | 
						    longjmp(onerror, 0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return str1;
 | 
				
			||||||
 | 
					    case UNARY_EXPR_CLASS:
 | 
				
			||||||
 | 
						str1 = eval_to_string(expr->members.unary_expr.arg);
 | 
				
			||||||
 | 
						switch(expr->members.unary_expr.oprtr) {
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
						    (void)str1;
 | 
				
			||||||
 | 
						    fprintf(stderr, "Unknown unary string operator: %d\n",
 | 
				
			||||||
 | 
							    expr->members.unary_expr.oprtr);
 | 
				
			||||||
 | 
						    abort();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					    case BINARY_EXPR_CLASS:
 | 
				
			||||||
 | 
						str1 = eval_to_string(expr->members.binary_expr.arg1);
 | 
				
			||||||
 | 
						str2 = eval_to_string(expr->members.binary_expr.arg2);
 | 
				
			||||||
 | 
						switch(expr->members.binary_expr.oprtr) {
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
						    (void)str1;  (void)str2;
 | 
				
			||||||
 | 
						    fprintf(stderr, "Unknown binary string operator: %d\n",
 | 
				
			||||||
 | 
							    expr->members.binary_expr.oprtr);
 | 
				
			||||||
 | 
						    abort();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
						fprintf(stderr, "Unknown expression class: %d\n", expr->class);
 | 
				
			||||||
 | 
						abort();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										223
									
								
								hw4/src/jobs.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										223
									
								
								hw4/src/jobs.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,223 @@
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <signal.h>
 | 
				
			||||||
 | 
					#include <fcntl.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					#include <wait.h>
 | 
				
			||||||
 | 
					#include <time.h>
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					#include <sys/time.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "mush.h"
 | 
				
			||||||
 | 
					#include "debug.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * This is the "jobs" module for Mush.
 | 
				
			||||||
 | 
					 * It maintains a table of jobs in various stages of execution, and it
 | 
				
			||||||
 | 
					 * provides functions for manipulating jobs.
 | 
				
			||||||
 | 
					 * Each job contains a pipeline, which is used to initialize the processes,
 | 
				
			||||||
 | 
					 * pipelines, and redirections that make up the job.
 | 
				
			||||||
 | 
					 * Each job has a job ID, which is an integer value that is used to identify
 | 
				
			||||||
 | 
					 * that job when calling the various job manipulation functions.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * At any given time, a job will have one of the following status values:
 | 
				
			||||||
 | 
					 * "new", "running", "completed", "aborted", "canceled".
 | 
				
			||||||
 | 
					 * A newly created job starts out in with status "new".
 | 
				
			||||||
 | 
					 * It changes to status "running" when the processes that make up the pipeline
 | 
				
			||||||
 | 
					 * for that job have been created.
 | 
				
			||||||
 | 
					 * A running job becomes "completed" at such time as all the processes in its
 | 
				
			||||||
 | 
					 * pipeline have terminated successfully.
 | 
				
			||||||
 | 
					 * A running job becomes "aborted" if the last process in its pipeline terminates
 | 
				
			||||||
 | 
					 * with a signal that is not the result of the pipeline having been canceled.
 | 
				
			||||||
 | 
					 * A running job becomes "canceled" if the jobs_cancel() function was called
 | 
				
			||||||
 | 
					 * to cancel it and in addition the last process in the pipeline subsequently
 | 
				
			||||||
 | 
					 * terminated with signal SIGKILL.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * In general, there will be other state information stored for each job,
 | 
				
			||||||
 | 
					 * as required by the implementation of the various functions in this module.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief  Initialize the jobs module.
 | 
				
			||||||
 | 
					 * @details  This function is used to initialize the jobs module.
 | 
				
			||||||
 | 
					 * It must be called exactly once, before any other functions of this
 | 
				
			||||||
 | 
					 * module are called.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @return 0 if initialization is successful, otherwise -1.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int jobs_init(void) {
 | 
				
			||||||
 | 
					    // TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					    abort();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief  Finalize the jobs module.
 | 
				
			||||||
 | 
					 * @details  This function is used to finalize the jobs module.
 | 
				
			||||||
 | 
					 * It must be called exactly once when job processing is to be terminated,
 | 
				
			||||||
 | 
					 * before the program exits.  It should cancel all jobs that have not
 | 
				
			||||||
 | 
					 * yet terminated, wait for jobs that have been cancelled to terminate,
 | 
				
			||||||
 | 
					 * and then expunge all jobs before returning.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @return 0 if finalization is completely successful, otherwise -1.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int jobs_fini(void) {
 | 
				
			||||||
 | 
					    // TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					    abort();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief  Print the current jobs table.
 | 
				
			||||||
 | 
					 * @details  This function is used to print the current contents of the jobs
 | 
				
			||||||
 | 
					 * table to a specified output stream.  The output should consist of one line
 | 
				
			||||||
 | 
					 * per existing job.  Each line should have the following format:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *    <jobid>\t<pgid>\t<status>\t<pipeline>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * where <jobid> is the numeric job ID of the job, <status> is one of the
 | 
				
			||||||
 | 
					 * following strings: "new", "running", "completed", "aborted", or "canceled",
 | 
				
			||||||
 | 
					 * and <pipeline> is the job's pipeline, as printed by function show_pipeline()
 | 
				
			||||||
 | 
					 * in the syntax module.  The \t stand for TAB characters.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param file  The output stream to which the job table is to be printed.
 | 
				
			||||||
 | 
					 * @return 0  If the jobs table was successfully printed, -1 otherwise.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int jobs_show(FILE *file) {
 | 
				
			||||||
 | 
					    // TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					    abort();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief  Create a new job to run a pipeline.
 | 
				
			||||||
 | 
					 * @details  This function creates a new job and starts it running a specified
 | 
				
			||||||
 | 
					 * pipeline.  The pipeline will consist of a "leader" process, which is the direct
 | 
				
			||||||
 | 
					 * child of the process that calls this function, plus one child of the leader
 | 
				
			||||||
 | 
					 * process to run each command in the pipeline.  All processes in the pipeline
 | 
				
			||||||
 | 
					 * should have a process group ID that is equal to the process ID of the leader.
 | 
				
			||||||
 | 
					 * The leader process should wait for all of its children to terminate before
 | 
				
			||||||
 | 
					 * terminating itself.  The leader should return the exit status of the process
 | 
				
			||||||
 | 
					 * running the last command in the pipeline as its own exit status, if that
 | 
				
			||||||
 | 
					 * process terminated normally.  If the last process terminated with a signal,
 | 
				
			||||||
 | 
					 * then the leader should terminate via SIGABRT.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * If the "capture_output" flag is set for the pipeline, then the standard output
 | 
				
			||||||
 | 
					 * of the last process in the pipeline should be redirected to be the same as
 | 
				
			||||||
 | 
					 * the standard output of the pipeline leader, and this output should go via a
 | 
				
			||||||
 | 
					 * pipe to the main Mush process, where it should be read and saved in the data
 | 
				
			||||||
 | 
					 * store as the value of a variable, as described in the assignment handout.
 | 
				
			||||||
 | 
					 * If "capture_output" is not set for the pipeline, but "output_file" is non-NULL,
 | 
				
			||||||
 | 
					 * then the standard output of the last process in the pipeline should be redirected
 | 
				
			||||||
 | 
					 * to the specified output file.   If "input_file" is set for the pipeline, then
 | 
				
			||||||
 | 
					 * the standard input of the process running the first command in the pipeline should
 | 
				
			||||||
 | 
					 * be redirected from the specified input file.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param pline  The pipeline to be run.  The jobs module expects this object
 | 
				
			||||||
 | 
					 * to be valid for as long as it requires, and it expects to be able to free this
 | 
				
			||||||
 | 
					 * object when it is finished with it.  This means that the caller should not pass
 | 
				
			||||||
 | 
					 * a pipeline object that is shared with any other data structure, but rather should
 | 
				
			||||||
 | 
					 * make a copy to be passed to this function.
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * @return  -1 if the pipeline could not be initialized properly, otherwise the
 | 
				
			||||||
 | 
					 * value returned is the job ID assigned to the pipeline.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int jobs_run(PIPELINE *pline) {
 | 
				
			||||||
 | 
					    // TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					    abort();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief  Wait for a job to terminate.
 | 
				
			||||||
 | 
					 * @details  This function is used to wait for the job with a specified job ID
 | 
				
			||||||
 | 
					 * to terminate.  A job has terminated when it has entered the COMPLETED, ABORTED,
 | 
				
			||||||
 | 
					 * or CANCELED state.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param  jobid  The job ID of the job to wait for.
 | 
				
			||||||
 | 
					 * @return  the exit status of the job leader, as returned by waitpid(),
 | 
				
			||||||
 | 
					 * or -1 if any error occurs that makes it impossible to wait for the specified job.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int jobs_wait(int jobid) {
 | 
				
			||||||
 | 
					    // TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					    abort();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief  Poll to find out if a job has terminated.
 | 
				
			||||||
 | 
					 * @details  This function is used to poll whether the job with the specified ID
 | 
				
			||||||
 | 
					 * has terminated.  This is similar to jobs_wait(), except that this function returns
 | 
				
			||||||
 | 
					 * immediately without waiting if the job has not yet terminated.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param  jobid  The job ID of the job to wait for.
 | 
				
			||||||
 | 
					 * @return  the exit status of the job leader, as returned by waitpid(), if the job
 | 
				
			||||||
 | 
					 * has terminated, or -1 if the job has not yet terminated or if any other error occurs.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int jobs_poll(int jobid) {
 | 
				
			||||||
 | 
					    // TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					    abort();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief  Expunge a terminated job from the jobs table.
 | 
				
			||||||
 | 
					 * @details  This function is used to expunge (remove) a job that has terminated from
 | 
				
			||||||
 | 
					 * the jobs table, so that space in the table can be used to start some new job.
 | 
				
			||||||
 | 
					 * In order to be expunged, a job must have terminated; if an attempt is made to expunge
 | 
				
			||||||
 | 
					 * a job that has not yet terminated, it is an error.  Any resources (exit status,
 | 
				
			||||||
 | 
					 * open pipes, captured output, etc.) that were being used by the job are finalized
 | 
				
			||||||
 | 
					 * and/or freed and will no longer be available.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param  jobid  The job ID of the job to expunge.
 | 
				
			||||||
 | 
					 * @return  0 if the job was successfully expunged, -1 if the job could not be expunged.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int jobs_expunge(int jobid) {
 | 
				
			||||||
 | 
					    // TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					    abort();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief  Attempt to cancel a job.
 | 
				
			||||||
 | 
					 * @details  This function is used to attempt to cancel a running job.
 | 
				
			||||||
 | 
					 * In order to be canceled, the job must not yet have terminated and there
 | 
				
			||||||
 | 
					 * must not have been any previous attempt to cancel the job.
 | 
				
			||||||
 | 
					 * Cancellation is attempted by sending SIGKILL to the process group associated
 | 
				
			||||||
 | 
					 * with the job.  Cancellation becomes successful, and the job actually enters the canceled
 | 
				
			||||||
 | 
					 * state, at such subsequent time as the job leader terminates as a result of SIGKILL.
 | 
				
			||||||
 | 
					 * If after attempting cancellation, the job leader terminates other than as a result
 | 
				
			||||||
 | 
					 * of SIGKILL, then cancellation is not successful and the state of the job is either
 | 
				
			||||||
 | 
					 * COMPLETED or ABORTED, depending on how the job leader terminated.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param  jobid  The job ID of the job to cancel.
 | 
				
			||||||
 | 
					 * @return  0 if cancellation was successfully initiated, -1 if the job was already
 | 
				
			||||||
 | 
					 * terminated, a previous attempt had been made to cancel the job, or any other
 | 
				
			||||||
 | 
					 * error occurred.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int jobs_cancel(int jobid) {
 | 
				
			||||||
 | 
					    // TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					    abort();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief  Get the captured output of a job.
 | 
				
			||||||
 | 
					 * @details  This function is used to retrieve output that was captured from a job
 | 
				
			||||||
 | 
					 * that has terminated, but that has not yet been expunged.  Output is captured for a job
 | 
				
			||||||
 | 
					 * when the "capture_output" flag is set for its pipeline.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param  jobid  The job ID of the job for which captured output is to be retrieved.
 | 
				
			||||||
 | 
					 * @return  The captured output, if the job has terminated and there is captured
 | 
				
			||||||
 | 
					 * output available, otherwise NULL.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					char *jobs_get_output(int jobid) {
 | 
				
			||||||
 | 
					    // TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					    abort();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief  Pause waiting for a signal indicating a potential job status change.
 | 
				
			||||||
 | 
					 * @details  When this function is called it blocks until some signal has been
 | 
				
			||||||
 | 
					 * received, at which point the function returns.  It is used to wait for a
 | 
				
			||||||
 | 
					 * potential job status change without consuming excessive amounts of CPU time.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @return -1 if any error occurred, 0 otherwise.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int jobs_pause(void) {
 | 
				
			||||||
 | 
					    // TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					    abort();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										12
									
								
								hw4/src/main.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								hw4/src/main.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,12 @@
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "mush.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(int argc, char *argv[]) {
 | 
				
			||||||
 | 
					    jobs_init();
 | 
				
			||||||
 | 
					    exec_interactive();
 | 
				
			||||||
 | 
					    jobs_fini();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										2219
									
								
								hw4/src/mush.lex.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2219
									
								
								hw4/src/mush.lex.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										2418
									
								
								hw4/src/mush.tab.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2418
									
								
								hw4/src/mush.tab.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										136
									
								
								hw4/src/program.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										136
									
								
								hw4/src/program.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,136 @@
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "mush.h"
 | 
				
			||||||
 | 
					#include "debug.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * This is the "program store" module for Mush.
 | 
				
			||||||
 | 
					 * It maintains a set of numbered statements, along with a "program counter"
 | 
				
			||||||
 | 
					 * that indicates the current point of execution, which is either before all
 | 
				
			||||||
 | 
					 * statements, after all statements, or in between two statements.
 | 
				
			||||||
 | 
					 * There should be no fixed limit on the number of statements that the program
 | 
				
			||||||
 | 
					 * store can hold.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief  Output a listing of the current contents of the program store.
 | 
				
			||||||
 | 
					 * @details  This function outputs a listing of the current contents of the
 | 
				
			||||||
 | 
					 * program store.  Statements are listed in increasing order of their line
 | 
				
			||||||
 | 
					 * number.  The current position of the program counter is indicated by
 | 
				
			||||||
 | 
					 * a line containing only the string "-->" at the current program counter
 | 
				
			||||||
 | 
					 * position.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param out  The stream to which to output the listing.
 | 
				
			||||||
 | 
					 * @return  0 if successful, -1 if any error occurred.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int prog_list(FILE *out) {
 | 
				
			||||||
 | 
					    // TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					    abort();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief  Insert a new statement into the program store.
 | 
				
			||||||
 | 
					 * @details  This function inserts a new statement into the program store.
 | 
				
			||||||
 | 
					 * The statement must have a line number.  If the line number is the same as
 | 
				
			||||||
 | 
					 * that of an existing statement, that statement is replaced.
 | 
				
			||||||
 | 
					 * The program store assumes the responsibility for ultimately freeing any
 | 
				
			||||||
 | 
					 * statement that is inserted using this function.
 | 
				
			||||||
 | 
					 * Insertion of new statements preserves the value of the program counter:
 | 
				
			||||||
 | 
					 * if the position of the program counter was just before a particular statement
 | 
				
			||||||
 | 
					 * before insertion of a new statement, it will still be before that statement
 | 
				
			||||||
 | 
					 * after insertion, and if the position of the program counter was after all
 | 
				
			||||||
 | 
					 * statements before insertion of a new statement, then it will still be after
 | 
				
			||||||
 | 
					 * all statements after insertion.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param stmt  The statement to be inserted.
 | 
				
			||||||
 | 
					 * @return  0 if successful, -1 if any error occurred.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int prog_insert(STMT *stmt) {
 | 
				
			||||||
 | 
					    // TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					    abort();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief  Delete statements from the program store.
 | 
				
			||||||
 | 
					 * @details  This function deletes from the program store statements whose
 | 
				
			||||||
 | 
					 * line numbers fall in a specified range.  Any deleted statements are freed.
 | 
				
			||||||
 | 
					 * Deletion of statements preserves the value of the program counter:
 | 
				
			||||||
 | 
					 * if before deletion the program counter pointed to a position just before
 | 
				
			||||||
 | 
					 * a statement that was not among those to be deleted, then after deletion the
 | 
				
			||||||
 | 
					 * program counter will still point the position just before that same statement.
 | 
				
			||||||
 | 
					 * If before deletion the program counter pointed to a position just before
 | 
				
			||||||
 | 
					 * a statement that was among those to be deleted, then after deletion the
 | 
				
			||||||
 | 
					 * program counter will point to the first statement beyond those deleted,
 | 
				
			||||||
 | 
					 * if such a statement exists, otherwise the program counter will point to
 | 
				
			||||||
 | 
					 * the end of the program.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param min  Lower end of the range of line numbers to be deleted.
 | 
				
			||||||
 | 
					 * @param max  Upper end of the range of line numbers to be deleted.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int prog_delete(int min, int max) {
 | 
				
			||||||
 | 
					    // TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					    abort();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief  Reset the program counter to the beginning of the program.
 | 
				
			||||||
 | 
					 * @details  This function resets the program counter to point just
 | 
				
			||||||
 | 
					 * before the first statement in the program.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void prog_reset(void) {
 | 
				
			||||||
 | 
					    // TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					    abort();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief  Fetch the next program statement.
 | 
				
			||||||
 | 
					 * @details  This function fetches and returns the first program
 | 
				
			||||||
 | 
					 * statement after the current program counter position.  The program
 | 
				
			||||||
 | 
					 * counter position is not modified.  The returned pointer should not
 | 
				
			||||||
 | 
					 * be used after any subsequent call to prog_delete that deletes the
 | 
				
			||||||
 | 
					 * statement from the program store.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @return  The first program statement after the current program
 | 
				
			||||||
 | 
					 * counter position, if any, otherwise NULL.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					STMT *prog_fetch(void) {
 | 
				
			||||||
 | 
					    // TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					    abort();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief  Advance the program counter to the next existing statement.
 | 
				
			||||||
 | 
					 * @details  This function advances the program counter by one statement
 | 
				
			||||||
 | 
					 * from its original position and returns the statement just after the
 | 
				
			||||||
 | 
					 * new position.  The returned pointer should not be used after any
 | 
				
			||||||
 | 
					 * subsequent call to prog_delete that deletes the statement from the
 | 
				
			||||||
 | 
					 * program store.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @return The first program statement after the new program counter
 | 
				
			||||||
 | 
					 * position, if any, otherwise NULL.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					STMT *prog_next() {
 | 
				
			||||||
 | 
					    // TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					    abort();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief  Perform a "go to" operation on the program store.
 | 
				
			||||||
 | 
					 * @details  This function performs a "go to" operation on the program
 | 
				
			||||||
 | 
					 * store, by resetting the program counter to point to the position just
 | 
				
			||||||
 | 
					 * before the statement with the specified line number.
 | 
				
			||||||
 | 
					 * The statement pointed at by the new program counter is returned.
 | 
				
			||||||
 | 
					 * If there is no statement with the specified line number, then no
 | 
				
			||||||
 | 
					 * change is made to the program counter and NULL is returned.
 | 
				
			||||||
 | 
					 * Any returned statement should only be regarded as valid as long
 | 
				
			||||||
 | 
					 * as no calls to prog_delete are made that delete that statement from
 | 
				
			||||||
 | 
					 * the program store.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @return  The statement having the specified line number, if such a
 | 
				
			||||||
 | 
					 * statement exists, otherwise NULL.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					STMT *prog_goto(int lineno) {
 | 
				
			||||||
 | 
					    // TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					    abort();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										102
									
								
								hw4/src/store.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								hw4/src/store.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,102 @@
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * This is the "data store" module for Mush.
 | 
				
			||||||
 | 
					 * It maintains a mapping from variable names to values.
 | 
				
			||||||
 | 
					 * The values of variables are stored as strings.
 | 
				
			||||||
 | 
					 * However, the module provides functions for setting and retrieving
 | 
				
			||||||
 | 
					 * the value of a variable as an integer.  Setting a variable to
 | 
				
			||||||
 | 
					 * an integer value causes the value of the variable to be set to
 | 
				
			||||||
 | 
					 * a string representation of that integer.  Retrieving the value of
 | 
				
			||||||
 | 
					 * a variable as an integer is possible if the current value of the
 | 
				
			||||||
 | 
					 * variable is the string representation of an integer.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief  Get the current value of a variable as a string.
 | 
				
			||||||
 | 
					 * @details  This function retrieves the current value of a variable
 | 
				
			||||||
 | 
					 * as a string.  If the variable has no value, then NULL is returned.
 | 
				
			||||||
 | 
					 * Any string returned remains "owned" by the data store module;
 | 
				
			||||||
 | 
					 * the caller should not attempt to free the string or to use it
 | 
				
			||||||
 | 
					 * after any subsequent call that would modify the value of the variable
 | 
				
			||||||
 | 
					 * whose value was retrieved.  If the caller needs to use the string for
 | 
				
			||||||
 | 
					 * an indefinite period, a copy should be made immediately.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param  var  The variable whose value is to be retrieved.
 | 
				
			||||||
 | 
					 * @return  A string that is the current value of the variable, if any,
 | 
				
			||||||
 | 
					 * otherwise NULL.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					char *store_get_string(char *var) {
 | 
				
			||||||
 | 
					    // TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					    abort();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief  Get the current value of a variable as an integer.
 | 
				
			||||||
 | 
					 * @details  This retrieves the current value of a variable and
 | 
				
			||||||
 | 
					 * attempts to interpret it as an integer.  If this is possible,
 | 
				
			||||||
 | 
					 * then the integer value is stored at the pointer provided by
 | 
				
			||||||
 | 
					 * the caller.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param  var  The variable whose value is to be retrieved.
 | 
				
			||||||
 | 
					 * @param  valp  Pointer at which the returned value is to be stored.
 | 
				
			||||||
 | 
					 * @return  If the specified variable has no value or the value
 | 
				
			||||||
 | 
					 * cannot be interpreted as an integer, then -1 is returned,
 | 
				
			||||||
 | 
					 * otherwise 0 is returned.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int store_get_int(char *var, long *valp) {
 | 
				
			||||||
 | 
					    // TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					    abort();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief  Set the value of a variable as a string.
 | 
				
			||||||
 | 
					 * @details  This function sets the current value of a specified
 | 
				
			||||||
 | 
					 * variable to be a specified string.  If the variable already
 | 
				
			||||||
 | 
					 * has a value, then that value is replaced.  If the specified
 | 
				
			||||||
 | 
					 * value is NULL, then any existing value of the variable is removed
 | 
				
			||||||
 | 
					 * and the variable becomes un-set.  Ownership of the variable and
 | 
				
			||||||
 | 
					 * the value strings is not transferred to the data store module as
 | 
				
			||||||
 | 
					 * a result of this call; the data store module makes such copies of
 | 
				
			||||||
 | 
					 * these strings as it may require.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param  var  The variable whose value is to be set.
 | 
				
			||||||
 | 
					 * @param  val  The value to set, or NULL if the variable is to become
 | 
				
			||||||
 | 
					 * un-set.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int store_set_string(char *var, char *val) {
 | 
				
			||||||
 | 
					    // TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					    abort();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief  Set the value of a variable as an integer.
 | 
				
			||||||
 | 
					 * @details  This function sets the current value of a specified
 | 
				
			||||||
 | 
					 * variable to be a specified integer.  If the variable already
 | 
				
			||||||
 | 
					 * has a value, then that value is replaced.  Ownership of the variable
 | 
				
			||||||
 | 
					 * string is not transferred to the data store module as a result of
 | 
				
			||||||
 | 
					 * this call; the data store module makes such copies of this string
 | 
				
			||||||
 | 
					 * as it may require.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param  var  The variable whose value is to be set.
 | 
				
			||||||
 | 
					 * @param  val  The value to set.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int store_set_int(char *var, long val) {
 | 
				
			||||||
 | 
					    // TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					    abort();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief  Print the current contents of the data store.
 | 
				
			||||||
 | 
					 * @details  This function prints the current contents of the data store
 | 
				
			||||||
 | 
					 * to the specified output stream.  The format is not specified; this
 | 
				
			||||||
 | 
					 * function is intended to be used for debugging purposes.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param f  The stream to which the store contents are to be printed.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void store_show(FILE *f) {
 | 
				
			||||||
 | 
					    // TO BE IMPLEMENTED
 | 
				
			||||||
 | 
					    abort();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										357
									
								
								hw4/src/syntax.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										357
									
								
								hw4/src/syntax.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,357 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * DO NOT MODIFY THE CONTENTS OF THIS FILE.
 | 
				
			||||||
 | 
					 * IT WILL BE REPLACED DURING GRADING
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "syntax.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Mush: Functions for manipulating syntax trees.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void show_stmt(FILE *file, STMT *stmt) {
 | 
				
			||||||
 | 
					    show_lineno(file, stmt->lineno);
 | 
				
			||||||
 | 
					    switch(stmt->class) {
 | 
				
			||||||
 | 
					    case LIST_STMT_CLASS:
 | 
				
			||||||
 | 
						fprintf(file, "list");
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case DELETE_STMT_CLASS:
 | 
				
			||||||
 | 
						fprintf(file, "delete %d, %d",
 | 
				
			||||||
 | 
							stmt->members.delete_stmt.from,
 | 
				
			||||||
 | 
							stmt->members.delete_stmt.to);
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case RUN_STMT_CLASS:
 | 
				
			||||||
 | 
						fprintf(file, "run");
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case CONT_STMT_CLASS:
 | 
				
			||||||
 | 
						fprintf(file, "cont");
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case STOP_STMT_CLASS:
 | 
				
			||||||
 | 
						fprintf(file, "stop");
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case FG_STMT_CLASS:
 | 
				
			||||||
 | 
						show_pipeline(file, stmt->members.sys_stmt.pipeline);
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case BG_STMT_CLASS:
 | 
				
			||||||
 | 
						show_pipeline(file, stmt->members.sys_stmt.pipeline);
 | 
				
			||||||
 | 
						fprintf(file, "& ");
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case WAIT_STMT_CLASS:
 | 
				
			||||||
 | 
						fprintf(file, "wait ");
 | 
				
			||||||
 | 
						show_expr(file, stmt->members.jobctl_stmt.expr, 0);
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case POLL_STMT_CLASS:
 | 
				
			||||||
 | 
						fprintf(file, "poll ");
 | 
				
			||||||
 | 
						show_expr(file, stmt->members.jobctl_stmt.expr, 0);
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case CANCEL_STMT_CLASS:
 | 
				
			||||||
 | 
						fprintf(file, "cancel ");
 | 
				
			||||||
 | 
						show_expr(file, stmt->members.jobctl_stmt.expr, 0);
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case PAUSE_STMT_CLASS:
 | 
				
			||||||
 | 
						fprintf(file, "pause");
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case SET_STMT_CLASS:
 | 
				
			||||||
 | 
						fprintf(file, "set ");
 | 
				
			||||||
 | 
						fprintf(file, "%s = ", stmt->members.set_stmt.name);
 | 
				
			||||||
 | 
						show_expr(file, stmt->members.set_stmt.expr, 0);
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case UNSET_STMT_CLASS:
 | 
				
			||||||
 | 
						fprintf(file, "unset ");
 | 
				
			||||||
 | 
						fprintf(file, "%s", stmt->members.unset_stmt.name);
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case IF_STMT_CLASS:
 | 
				
			||||||
 | 
						fprintf(file, "if ");
 | 
				
			||||||
 | 
						show_expr(file, stmt->members.if_stmt.expr, 0);
 | 
				
			||||||
 | 
						fprintf(file, " goto %d", stmt->members.if_stmt.lineno);
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case GOTO_STMT_CLASS:
 | 
				
			||||||
 | 
						fprintf(file, "goto %d", stmt->members.goto_stmt.lineno);
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case SOURCE_STMT_CLASS:
 | 
				
			||||||
 | 
						fprintf(file, "source %s", stmt->members.source_stmt.file);
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
						fprintf(stderr, "Unknown statement class: %d\n", stmt->class);
 | 
				
			||||||
 | 
						abort();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    fprintf(file, "\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void show_pipeline(FILE *file, PIPELINE *pline) {
 | 
				
			||||||
 | 
					    COMMAND *cmds = pline->commands;
 | 
				
			||||||
 | 
					    while(cmds) {
 | 
				
			||||||
 | 
						show_command(file, cmds);
 | 
				
			||||||
 | 
						if(cmds->next)
 | 
				
			||||||
 | 
						    fprintf(file, " | ");
 | 
				
			||||||
 | 
						cmds = cmds->next;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if(pline->input_file)
 | 
				
			||||||
 | 
						fprintf(file, " < %s", pline->input_file);
 | 
				
			||||||
 | 
					    if(pline->capture_output)
 | 
				
			||||||
 | 
						fprintf(file, " >@");
 | 
				
			||||||
 | 
					    if(pline->output_file)
 | 
				
			||||||
 | 
						fprintf(file, " > %s", pline->output_file);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void show_command(FILE *file, COMMAND *cmd) {
 | 
				
			||||||
 | 
					    ARG *arg = cmd->args;
 | 
				
			||||||
 | 
					    while(arg) {
 | 
				
			||||||
 | 
						show_expr(file, arg->expr, 0);
 | 
				
			||||||
 | 
						if(arg->next)
 | 
				
			||||||
 | 
						    fprintf(file, " ");
 | 
				
			||||||
 | 
						arg = arg->next;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void show_expr(FILE *file, EXPR *expr, int parens) {
 | 
				
			||||||
 | 
					    switch(expr->class) {
 | 
				
			||||||
 | 
					    case LIT_EXPR_CLASS:
 | 
				
			||||||
 | 
						fprintf(file, "%s", expr->members.value);
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case NUM_EXPR_CLASS:
 | 
				
			||||||
 | 
						fprintf(file, "#%s", expr->members.variable);
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case STRING_EXPR_CLASS:
 | 
				
			||||||
 | 
						fprintf(file, "$%s", expr->members.variable);
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case UNARY_EXPR_CLASS:
 | 
				
			||||||
 | 
						if(parens)
 | 
				
			||||||
 | 
						    fprintf(file, "(");
 | 
				
			||||||
 | 
						show_oprtr(file, expr->members.unary_expr.oprtr);
 | 
				
			||||||
 | 
						fprintf(file, " ");
 | 
				
			||||||
 | 
						show_expr(file, expr->members.unary_expr.arg, 1);
 | 
				
			||||||
 | 
						if(parens)
 | 
				
			||||||
 | 
						    fprintf(file, ")");
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case BINARY_EXPR_CLASS:
 | 
				
			||||||
 | 
						if(parens)
 | 
				
			||||||
 | 
						    fprintf(file, "(");
 | 
				
			||||||
 | 
						show_expr(file, expr->members.binary_expr.arg1, 1);
 | 
				
			||||||
 | 
						fprintf(file, " ");
 | 
				
			||||||
 | 
						show_oprtr(file, expr->members.binary_expr.oprtr);
 | 
				
			||||||
 | 
						fprintf(file, " ");
 | 
				
			||||||
 | 
						show_expr(file, expr->members.binary_expr.arg2, 1);
 | 
				
			||||||
 | 
						if(parens)
 | 
				
			||||||
 | 
						    fprintf(file, ")");
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
						fprintf(stderr, "Unknown expression class: %d\n", expr->class);
 | 
				
			||||||
 | 
						abort();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void show_oprtr(FILE *file, OPRTR oprtr) {
 | 
				
			||||||
 | 
					    switch(oprtr) {
 | 
				
			||||||
 | 
					    case PLUS_OPRTR:
 | 
				
			||||||
 | 
						fprintf(file, "+");
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case MINUS_OPRTR:
 | 
				
			||||||
 | 
						fprintf(file, "-");
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case TIMES_OPRTR:
 | 
				
			||||||
 | 
						fprintf(file, "*");
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case DIVIDE_OPRTR:
 | 
				
			||||||
 | 
						fprintf(file, "/");
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case MOD_OPRTR:
 | 
				
			||||||
 | 
						fprintf(file, "%s", "%");
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case AND_OPRTR:
 | 
				
			||||||
 | 
						fprintf(file, "&&");
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case OR_OPRTR:
 | 
				
			||||||
 | 
						fprintf(file, "||");
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case NOT_OPRTR:
 | 
				
			||||||
 | 
						fprintf(file, "!");
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case EQUAL_OPRTR:
 | 
				
			||||||
 | 
						fprintf(file, "==");
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case LESS_OPRTR:
 | 
				
			||||||
 | 
						fprintf(file, "<");
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case GREATER_OPRTR:
 | 
				
			||||||
 | 
						fprintf(file, ">");
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case LESSEQ_OPRTR:
 | 
				
			||||||
 | 
						fprintf(file, "<=");
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case GREATEQ_OPRTR:
 | 
				
			||||||
 | 
						fprintf(file, ">=");
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
						fprintf(stderr, "Unknown operator: %d\n", oprtr);
 | 
				
			||||||
 | 
						abort();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void show_lineno(FILE *file, int lineno) {
 | 
				
			||||||
 | 
					    if(lineno)
 | 
				
			||||||
 | 
						fprintf(file, "%7d\t", lineno);
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
						fprintf(file, "\t");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void free_stmt(STMT *stmt) {
 | 
				
			||||||
 | 
					    if(stmt == NULL)  // Produced by error recovery production
 | 
				
			||||||
 | 
						return;
 | 
				
			||||||
 | 
					    switch(stmt->class) {
 | 
				
			||||||
 | 
					    case LIST_STMT_CLASS:
 | 
				
			||||||
 | 
					    case DELETE_STMT_CLASS:
 | 
				
			||||||
 | 
					    case RUN_STMT_CLASS:
 | 
				
			||||||
 | 
					    case CONT_STMT_CLASS:
 | 
				
			||||||
 | 
					    case STOP_STMT_CLASS:
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case FG_STMT_CLASS:
 | 
				
			||||||
 | 
						free_pipeline(stmt->members.sys_stmt.pipeline);
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case BG_STMT_CLASS:
 | 
				
			||||||
 | 
						free_pipeline(stmt->members.sys_stmt.pipeline);
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case GOTO_STMT_CLASS:
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case WAIT_STMT_CLASS:
 | 
				
			||||||
 | 
					    case POLL_STMT_CLASS:
 | 
				
			||||||
 | 
					    case CANCEL_STMT_CLASS:
 | 
				
			||||||
 | 
						free_expr(stmt->members.jobctl_stmt.expr);
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case SET_STMT_CLASS:
 | 
				
			||||||
 | 
						free(stmt->members.set_stmt.name);
 | 
				
			||||||
 | 
						free_expr(stmt->members.set_stmt.expr);
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case UNSET_STMT_CLASS:
 | 
				
			||||||
 | 
						free(stmt->members.unset_stmt.name);
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case IF_STMT_CLASS:
 | 
				
			||||||
 | 
						free_expr(stmt->members.if_stmt.expr);
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case SOURCE_STMT_CLASS:
 | 
				
			||||||
 | 
						free(stmt->members.source_stmt.file);
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case PAUSE_STMT_CLASS:
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
						fprintf(stderr, "Unknown statement class: %d\n", stmt->class);
 | 
				
			||||||
 | 
						abort();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    free(stmt);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void free_pipeline(PIPELINE *pline) {
 | 
				
			||||||
 | 
					    free_commands(pline->commands);
 | 
				
			||||||
 | 
					    if(pline->input_file)
 | 
				
			||||||
 | 
						free(pline->input_file);
 | 
				
			||||||
 | 
					    if(pline->output_file)
 | 
				
			||||||
 | 
						free(pline->output_file);
 | 
				
			||||||
 | 
					    free(pline);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void free_commands(COMMAND *cmd) {
 | 
				
			||||||
 | 
					    if(cmd->next)
 | 
				
			||||||
 | 
						free_commands(cmd->next);
 | 
				
			||||||
 | 
					    if(cmd->args)
 | 
				
			||||||
 | 
						free_args(cmd->args);
 | 
				
			||||||
 | 
					    free(cmd);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void free_args(ARG *args) {
 | 
				
			||||||
 | 
					    if(args->next)
 | 
				
			||||||
 | 
						free_args(args->next);
 | 
				
			||||||
 | 
					    free_expr(args->expr);
 | 
				
			||||||
 | 
					    free(args);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void free_expr(EXPR *expr) {
 | 
				
			||||||
 | 
					    switch(expr->class) {
 | 
				
			||||||
 | 
					    case LIT_EXPR_CLASS:
 | 
				
			||||||
 | 
						free(expr->members.value);
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case NUM_EXPR_CLASS:
 | 
				
			||||||
 | 
						free(expr->members.variable);
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case STRING_EXPR_CLASS:
 | 
				
			||||||
 | 
						free(expr->members.variable);
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case UNARY_EXPR_CLASS:
 | 
				
			||||||
 | 
						free_expr(expr->members.unary_expr.arg);
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case BINARY_EXPR_CLASS:
 | 
				
			||||||
 | 
						free_expr(expr->members.binary_expr.arg1);
 | 
				
			||||||
 | 
						free_expr(expr->members.binary_expr.arg2);
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
						fprintf(stderr, "Unknown expression class: %d\n", expr->class);
 | 
				
			||||||
 | 
						abort();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    free(expr);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PIPELINE *copy_pipeline(PIPELINE *pline) {
 | 
				
			||||||
 | 
					    if(!pline)
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					    PIPELINE *copy = calloc(sizeof(PIPELINE), 1);
 | 
				
			||||||
 | 
					    copy->commands = copy_commands(pline->commands);
 | 
				
			||||||
 | 
					    copy->capture_output = pline->capture_output;
 | 
				
			||||||
 | 
					    if(pline->input_file)
 | 
				
			||||||
 | 
						copy->input_file = strdup(pline->input_file);
 | 
				
			||||||
 | 
					    if(pline->output_file)
 | 
				
			||||||
 | 
						copy->output_file = strdup(pline->output_file);
 | 
				
			||||||
 | 
					    return(copy);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					COMMAND *copy_commands(COMMAND *cmd) {
 | 
				
			||||||
 | 
					    if(!cmd)
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					    COMMAND *copy = calloc(sizeof(COMMAND), 1);
 | 
				
			||||||
 | 
					    copy->next = copy_commands(cmd->next);
 | 
				
			||||||
 | 
					    copy->args = copy_args(cmd->args);
 | 
				
			||||||
 | 
					    return copy;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ARG *copy_args(ARG *args) {
 | 
				
			||||||
 | 
					    if(!args)
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					    ARG *copy = calloc(sizeof(ARG), 1);
 | 
				
			||||||
 | 
					    copy->next = copy_args(args->next);
 | 
				
			||||||
 | 
					    copy->expr = copy_expr(args->expr);
 | 
				
			||||||
 | 
					    return copy;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					EXPR *copy_expr(EXPR *expr) {
 | 
				
			||||||
 | 
					    if(!expr)
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					    EXPR *copy = calloc(sizeof(EXPR), 1);
 | 
				
			||||||
 | 
					    copy->class = expr->class;
 | 
				
			||||||
 | 
					    copy->type = expr->type;
 | 
				
			||||||
 | 
					    switch(expr->class) {
 | 
				
			||||||
 | 
					    case LIT_EXPR_CLASS:
 | 
				
			||||||
 | 
						copy->members.value = strdup(expr->members.value);
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case NUM_EXPR_CLASS:
 | 
				
			||||||
 | 
						copy->members.variable = strdup(expr->members.variable);
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case STRING_EXPR_CLASS:
 | 
				
			||||||
 | 
						copy->members.variable = strdup(expr->members.variable);
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case UNARY_EXPR_CLASS:
 | 
				
			||||||
 | 
						copy->members.unary_expr.oprtr = expr->members.unary_expr.oprtr;
 | 
				
			||||||
 | 
						copy->members.unary_expr.arg = copy_expr(expr->members.unary_expr.arg);
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    case BINARY_EXPR_CLASS:
 | 
				
			||||||
 | 
						copy->members.binary_expr.oprtr = expr->members.binary_expr.oprtr;
 | 
				
			||||||
 | 
						copy->members.binary_expr.arg1 = copy_expr(expr->members.binary_expr.arg1);
 | 
				
			||||||
 | 
						copy->members.binary_expr.arg2 = copy_expr(expr->members.binary_expr.arg2);
 | 
				
			||||||
 | 
						break;
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
						fprintf(stderr, "Unknown expression class: %d\n", expr->class);
 | 
				
			||||||
 | 
						abort();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return copy;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										19
									
								
								hw4/tests/base_tests.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								hw4/tests/base_tests.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,19 @@
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <sys/stat.h>
 | 
				
			||||||
 | 
					#include <criterion/criterion.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * This just checks if mush exits normally on an empty input.
 | 
				
			||||||
 | 
					 * It is not very interesting, unfortunately.
 | 
				
			||||||
 | 
					 * It is just a place holder where something more interesting might go.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					Test(basecode_suite, mush_eof_test, .timeout=20)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    char *cmd = "ulimit -t 10; bin/mush < /dev/null";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int code = WEXITSTATUS(system(cmd));
 | 
				
			||||||
 | 
					    cr_assert_eq(code, EXIT_SUCCESS,
 | 
				
			||||||
 | 
					                 "Program exited with %d instead of EXIT_SUCCESS",
 | 
				
			||||||
 | 
							 code);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user