Answered step by step
Verified Expert Solution
Link Copied!

Question

1 Approved Answer

Makefile: BIN = ./wish OBJS = wish.o wish_read.o wish_parse.o wish_yyparser.tab.o lex.yy.o CFLAGS = -Wall -pedantic -Wextra -Wcast-align -Wcast-qual -Wdisabled-optimization -Wformat=2 -Winit-self -Wmissing-include-dirs

image text in transcribedimage text in transcribed

Makefile:

BIN = ./wish

OBJS = wish.o wish_read.o wish_parse.o \

wish_yyparser.tab.o lex.yy.o

CFLAGS = -Wall -pedantic -Wextra -Wcast-align -Wcast-qual \

-Wdisabled-optimization -Wformat=2 -Winit-self \

-Wmissing-include-dirs -Wredundant-decls -Wshadow \

-Wstrict-overflow=5 -Wundef -Werror -Wno-unused \

-g -Wno-unused-result -O3 -Wlogical-op -Wno-strict-overflow

all: $(BIN)

$(BIN): $(OBJS)

$(CC) $(OBJS) -o $(BIN) -lreadline #-lefence

wish.o: wish.c wish.h

wish_read.o: wish_read.c wish.h

wish_parse.o: wish_yyparser.tab.h wish.h

wish_yyparser.tab.c wish_yyparser.tab.h: wish_yyparser.y

bison -d wish_yyparser.y

wish_yyparser.tab.o: wish_yyparser.tab.c wish.h

lex.yy.o: lex.yy.c wish.h wish_yyparser.tab.h

lex.yy.c: wish_yylexer.l

flex -I wish_yylexer.l

clean:

rm -f $(OBJS) $(BIN) lex.yy.c\

wish_yyparser.tab.c wish_yyparser.tab.h

valgrind: all

clear

valgrind --leak-check=full $(BIN)

wish_parse.c:

#include

#include "wish.h"

// https://en.wikipedia.org/wiki/Escape_sequences_in_C#Table_of_escape_sequences

char *wish_unquote(char * s) {

return s; // MODIFY!

}

// Do not modify this function

void yyerror(const char* s) {

fprintf(stderr, "Parse error: %s ", s);

}

char *wish_safe_getenv(char *s) {

return s;

}

wish_read.c:

#include

#include

#include

#include "wish.h"

char *wish_read_line(FILE *in) {

char buffer[WISH_MAX_INPUT + 2] = ""; // truncate the buffer

// Get a string and check its length

fgets(buffer, WISH_MAX_INPUT + 2, in);

if(strlen(buffer) > WISH_MAX_INPUT) {

fputs("wish: line too long ", stderr);

// Clean the rest of the line

int c = fgetc(in);

while (c != ' ' && c != EOF)

c = fgetc(in);

return NULL;

}

// Trim the line

strtok(buffer, " ");

// Check the line for being blank

for(size_t i = 0; i

if(!isspace(buffer[i])) {

// Alloate memory

char *line = malloc(strlen(buffer) + 1);

if (!line) // Too bad

abort();

strcat(line, buffer);

return line;

}

}

return NULL;

}

int wish_read_config(char *fname, int ok_if_missing) {

FILE *config;

// Check if the file exists

if(!(config = fopen(fname, "r"))) {

if (ok_if_missing)

return 0;

// Report missing

perror(fname);

return 1;

}

// Read the file line by line

while(!feof(config)) {

char *line = wish_read_line(config);

if(line) {

#ifdef DEBUG

fprintf(stderr, "%s ", line); // Only for debugging

#endif

free(line);

}

}

fclose(config);

return 0;

}

wish_yylexer.l:

%{

#include "wish.h"

#include "wish_yyparser.tab.h"

#ifdef __APPLE__

extern int yylex(void);

extern int yyparse(void);

#endif

char *wish_safe_getenv(char *s);

char *wish_unquote(char *s);

%}

%option noyywrap

digit [0-9]

letter [a-zA-Z_]

alnum {digit}|{letter}

string \"([^ \\\"]|\\.)*\"

quoted_string \'([^ \\\']|\\.)*\'

permitted {digit}|{letter}|[-%@_+\[\]\\/,\.:]

unsupported [;()*^?~{}`]

%%

"#".*" "? { /* comment */ }

exit { return YY_EXIT; }

pwd { return YY_PWD; }

cd { return YY_CD; }

\${alnum}+ { yylval.s = strdup(wish_safe_getenv(yytext + 1));

return YY_TOK; }

{permitted}+ { yylval.s = strdup(wish_unquote(yytext));

return YY_TOK; }

{quoted_string} { yytext[strlen(yytext) - 1] = 0;

yylval.s = strdup(yytext + 1);

return YY_TOK; }

{string} { yytext[strlen(yytext) - 1] = 0;

yylval.s = strdup(wish_unquote(yytext + 1));

return YY_TOK; }

"

">" { return YY_MORE; }

">>" { return YY_MOREMORE; }

"&" { return YY_AMP; }

"|" { return YY_BAR; }

"=" { return YY_SET; }

{unsupported} { fprintf(stderr, "Unsupported command: %c ", yytext[0]);

return YY_UNKNOWN;}

[\t \b\v ]+ { /* whitespaces */ }

. { fprintf(stderr, "Illegal character: %c ", yytext[0]);

return YY_UNKNOWN; }

%%

// The function returns 0 if there are no syntax errors and 1, otherwise

int wish_parse_command(char *command) {

YY_BUFFER_STATE buffer = yy_scan_string(command);

int retval = yyparse();

yylex_destroy();

return retval;

}

wish_yyparser:

%{

#include "wish.h"

int yylex();

void yyerror(const char* s);

%}

%union {

char *s;

}

%token YY_SET

%token YY_EXIT

%token YY_JOBS

%token YY_PWD

%token YY_CD

%token YY_UNKNOWN

%token YY_LESS

%token YY_MORE

%token YY_MOREMORE

%token YY_AMP

%token YY_BAR

%token YY_TOK

%start cmdline

%%

cmdline:

%empty /* an empty line is valid, too! Do nothing */

| redir_prog bg_mode

| in_prog pipe bg_mode

| arg YY_SET arg

| YY_PWD

| YY_CD arg

| YY_EXIT { /* ... */ }

pipe:

YY_BAR out_prog

| pipe YY_BAR out_prog

redir_prog:

prog

| prog any_redir

in_prog:

prog

| prog in_redir

out_prog:

prog

| prog out_redir

inout_redir:

in_redir out_redir

| out_redir in_redir

out_redir:

out1_redir

| out2_redir

any_redir:

in_redir

| out_redir

| inout_redir

in_redir: YY_LESS arg

out1_redir: YY_MORE arg

out2_redir: YY_MOREMORE arg

bg_mode:

%empty

| YY_AMP

prog:

args

args:

arg

| args arg

arg:

YY_TOK

%%

/* This section is empty */

wish.c:

#include

#include "wish.h"

int main(int argc, char *argv[])

{

// These two lines make the macOS C compiler happy.

// Otherwise, it complains about unused parameters.

(void)argc;

(void)argv;

char path[PATH_MAX];

char *home = getenv("HOME");

#ifdef DEBUG

home = "."; // So that you could place the config into the CWD

#endif

sprintf(path, "%s/%s", (home ? home : "."), WISH_CONFIG);

wish_read_config(path, 1);

// This is just a skeleton for your convenience

fputs(WISH_DEFAULT_PROMPT, stdout);

char *line = wish_read_line(stdin);

if(line)

free(line);

return EXIT_SUCCESS;

}

wish.conf:

echo 'hello, world!

# do not parse! a very long line --------------------------------------------------------------------

set good bad

aa

wish.h:

#ifndef WISH_H

#define WISH_H

#include

#include

#define DEBUG

#define WISH_MAX_INPUT 80 // really modest :)

#define WISH_DEFAULT_PROMPT "> "

#define WISH_CONFIG "wish.conf"

char *wish_read_line(FILE *in);

int wish_read_config(char *fname, int ok_if_missing);

#endif

Parsing Commands In this assignment, you are to implement and test function char *wish_unqiote(char *s); modify function void wish_read_config(char *fname); and explore the function int wish_parse command(char *command) and flex and bison parser code (provided). The new functions are in the files wish.parse.c, Wish yyparser.y (a bison file), and wish yylexer.l (a flex file). 1. Function char *wish_unquote(char *s) shall return the same string s in which each escape sequence 1 shall be replaced by its value. For example, a backslash 6 ' followed by an 6n, shall be replaced by a newline character 6n. 2. For this project stage, you must install bison and flex, free parser and lexer generators. You are not required to write your bison and flex rules but are encouraged to look into the provided files. Mac0S users: your default flex and bison are OLD; please upgrade them. File wish yylexer.I describes the tokens admissible on the wish command line. The tokens are described as regular expressions. For example, "\#", *" " "? represents a comment (a pound sign \#, followed by zero or more characters, optionally followed by a newline). Flex converts the input file into a C file (do not edit that file manually!) that provides the function yylex(). The function is a token generator: every time you call it, you get the next token from the command line. File wish yyparser.y recursively describes the grammar of the wish language, that is, what combinations of the tokens are admissible. For example, the command line must be either a program-with-redirection, possibly followed by an ampersand for background execution, an "in', program, followed by a pipe and possibly an ampersand, or a built-in command (lines 30-35). Furthermore, a program-with-redirection is either just a program or a program with "in-out" redirection (lines 41-43), etc. Bison converts the input file into a C file (do not edit that file manually!) that provides the function yyparse( . The function calls yylex() to read tokens, validates the stream of tokens against the grammar rules, and executes C actions (the code in curly braces) whenever an appropriate grammar structure is encountered. For ease of use, I wrapped yyparse( ) into another function int Wish_parse command (char *command) that takes the command line command, validates its syntax, and returns 1 or 0 , depending on whether or not the command line had syntax errors. You will use this function in the future to execute the command line. 3. Rewrite the main() function and wish_read_config() from your previous assignment. 3a. Call wish_parse command() after each successful call to Wish read line(). (Including the calls in wish read config()). Pass the value returned by wish_read_line( to wish_parse_command(). 3b. Add the main loop to the main() function. The loop shall run for as long as the global variable wish_exit (provided) is 0. The loop shall display the prompt, call wish_read_line( , and then call wish_parse_command( . 3c. Modify line 69 of wish yyparser.y: add an action that changes the value of wish_exit. You can now exit wish by typing exit on the command line

Step by Step Solution

There are 3 Steps involved in it

Step: 1

blur-text-image

Get Instant Access to Expert-Tailored Solutions

See step-by-step solutions with expert insights and AI powered tools for academic success

Step: 2

blur-text-image

Step: 3

blur-text-image

Ace Your Homework with AI

Get the answers you need in no time with our AI-driven, step-by-step assistance

Get Started

Recommended Textbook for

Database Management With Website Development Applications

Authors: Greg Riccardi

1st Edition

0201743876, 978-0201743876

More Books

Students also viewed these Databases questions

Question

What is Change Control and how does it operate?

Answered: 1 week ago

Question

How do Data Requirements relate to Functional Requirements?

Answered: 1 week ago