diff --git a/labs/07/Makefile b/labs/07/Makefile new file mode 100644 index 00000000..45b05af7 --- /dev/null +++ b/labs/07/Makefile @@ -0,0 +1,45 @@ +# Define the compiler and flags +CC = gcc +LEX = flex +YACC = bison +YFLAGS = -d +CFLAGS = -ll -ly -lcurl + +# Define the source files and output executable +LEX_SRC = chatbot.l +YACC_SRC = chatbot.y +LEX_OUT = chatbot.c +YACC_OUT = chatbot.tab.c +YACC_HEADER = chatbot.tab.h +EXEC = chatbot + +# Define the test input and output files +TEST_INPUT = in.txt +EXPECTED_OUTPUT = out.txt +ACTUAL_OUTPUT = actual_output.txt + +# Default target +all: $(EXEC) + +# Compile the executable +$(EXEC): $(LEX_OUT) $(YACC_OUT) + $(CC) $(LEX_OUT) $(YACC_OUT) -o $(EXEC) $(CFLAGS) + +# Generate the lex and yacc output files +$(LEX_OUT): $(LEX_SRC) + $(LEX) $(LEX_SRC) + +$(YACC_OUT): $(YACC_SRC) + $(YACC) $(YFLAGS) $(YACC_SRC) + +# Run the tests +test: $(EXEC) + ./$(EXEC) < $(TEST_INPUT) > $(ACTUAL_OUTPUT) + diff -u $(EXPECTED_OUTPUT) $(ACTUAL_OUTPUT) || true + +# Clean up the generated files +clean: + rm -f $(LEX_OUT) $(YACC_OUT) $(YACC_HEADER) $(EXEC) $(ACTUAL_OUTPUT) + +# Phony targets +.PHONY: all clean test diff --git a/labs/07/chatbot.l b/labs/07/chatbot.l new file mode 100644 index 00000000..82c76857 --- /dev/null +++ b/labs/07/chatbot.l @@ -0,0 +1,27 @@ +%{ +#include "chatbot.tab.h" +%} +%option outfile="chatbot.c" +%% + +hello|hi|hey { return HELLO; } +goodbye|bye { return GOODBYE; } +time { return TIME; } +what[[:space:]]is[[:space:]]the[[:space:]]time { return TIME; } +what[[:space:]]time[[:space:]]is[[:space:]]it { return TIME; } +what[[:space:]]is[[:space:]]your[[:space:]]name { return NAME; } +what[[:space:]]is[[:space:]]the[[:space:]]weather { return WEATHER; } +weather[[:space:]]in[[:space:]]([a-zA-Z ]+) { yylval.str = strdup(yytext + 11); return WEATHER_CITY; } +[0-9]+[[:space:]]*\+[[:space:]]*[0-9]+ { yylval.str = strdup(yytext); return ADD; } +[0-9]+[[:space:]]*-[[:space:]]*[0-9]+ { yylval.str = strdup(yytext); return SUB; } +[0-9]+[[:space:]]*\*[[:space:]]*[0-9]+ { yylval.str = strdup(yytext); return MUL; } +[0-9]+[[:space:]]*\/[[:space:]]*[0-9]+ { yylval.str = strdup(yytext); return DIV; } + +\n { return 0; } +. { return yytext[0]; } + +%% + +int yywrap() { + return 1; +} diff --git a/labs/07/chatbot.y b/labs/07/chatbot.y new file mode 100644 index 00000000..90f3bc65 --- /dev/null +++ b/labs/07/chatbot.y @@ -0,0 +1,154 @@ +%{ +#include +#include +#include +#include +#include + +void yyerror(const char *s); +int yylex(void); + +size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp) { + size_t total_size = size * nmemb; + strncat(userp, contents, total_size); + return total_size; +} + +void get_weather(char *buffer, size_t buffer_size, const char *city) { + CURL *curl; + CURLcode res; + char url[256]; + char *encoded_city; + + curl_global_init(CURL_GLOBAL_DEFAULT); + curl = curl_easy_init(); + if (curl) { + if (city) { + encoded_city = curl_easy_escape(curl, city, 0); + snprintf(url, sizeof(url), "https://wttr.in/%s?format=3", encoded_city); + curl_free(encoded_city); + } else { + snprintf(url, sizeof(url), "https://wttr.in/?format=3"); + } + + curl_easy_setopt(curl, CURLOPT_URL, url); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, buffer); + + res = curl_easy_perform(curl); + if (res != CURLE_OK) { + fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); + } + + curl_easy_cleanup(curl); + } + curl_global_cleanup(); +} + +void print_weather(const char *city) { + char buffer[10000] = {0}; + get_weather(buffer, sizeof(buffer), city); + + if (strlen(buffer) > 0) { + printf("Chatbot: %s", buffer); + } else { + printf("Chatbot: Sorry, I couldn't fetch the weather information.\n"); + } +} + +void perform_calculation(char *expr) { + char op; + int num1, num2, result; + sscanf(expr, "%d %c %d", &num1, &op, &num2); + + switch (op) { + case '+': + result = num1 + num2; + break; + case '-': + result = num1 - num2; + break; + case '*': + result = num1 * num2; + break; + case '/': + if (num2 != 0) + result = num1 / num2; + else { + printf("Chatbot: Cannot divide by zero.\n"); + return; + } + break; + default: + printf("Chatbot: Invalid operation.\n"); + return; + } + printf("Chatbot: The result of %d %c %d is %d.\n", num1, op, num2, result); +} + + +%} + +%union { + char *str; +} + +%token HELLO GOODBYE TIME NAME WEATHER WEATHER_CITY ADD SUB MUL DIV +%type WEATHER_CITY ADD SUB MUL DIV + + +%% + +chatbot : greeting + | farewell + | query + | name_query + | weather_query + | weather_city_query + | calculation + ; + +greeting : HELLO { printf("Chatbot: Hello! How can I help you today?\n"); } + ; + +farewell : GOODBYE { printf("Chatbot: Goodbye! Have a great day!\n"); } + ; + +query : TIME { + time_t now = time(NULL); + struct tm *local = localtime(&now); + printf("Chatbot: The current time is %02d:%02d.\n", local->tm_hour, local->tm_min); + } + ; +name_query : NAME { printf("Chatbot: My name is Chatbot. My creator wasn't very original!\n"); } + ; + +weather_query : WEATHER { + print_weather(NULL); + } + ; + +weather_city_query : WEATHER_CITY { + print_weather($1); free($1); + } + ; + +calculation : ADD { perform_calculation($1); free($1); } + | SUB { perform_calculation($1); free($1); } + | MUL { perform_calculation($1); free($1); } + | DIV { perform_calculation($1); free($1); } + ; + +%% + +int main() { + printf("Chatbot: Hi! You can greet me, ask for the time, inquire about the weather, I can help you with simple math expressions, or say goodbye.\n"); + while (yyparse() == 0) { + // Loop until end of input + } + return 0; +} + +void yyerror(const char *s) { + fprintf(stderr, "Chatbot: I didn't understand that.\n"); +} \ No newline at end of file diff --git a/labs/07/in.txt b/labs/07/in.txt new file mode 100644 index 00000000..09682409 --- /dev/null +++ b/labs/07/in.txt @@ -0,0 +1,10 @@ +hello +what is your name +what time is it +what is the weather +weather in Berlin +2+2 +3 * 4 +12 / 3 +22 - 7 +goodbye diff --git a/labs/07/out.txt b/labs/07/out.txt new file mode 100644 index 00000000..033df846 --- /dev/null +++ b/labs/07/out.txt @@ -0,0 +1,11 @@ +Chatbot: Hi! You can greet me, ask for the time, inquire about the weather, I can help you with simple math expressions, or say goodbye. +Chatbot: Hello! How can I help you today? +Chatbot: My name is Chatbot. My creator wasn't very original! +Chatbot: The current time is 19:29. +Chatbot: Guadalajara, Mexico: ☀️ +36°C +Chatbot: Berlin: ☀️ +18°C +Chatbot: The result of 2 + 2 is 4. +Chatbot: The result of 3 * 4 is 12. +Chatbot: The result of 12 / 3 is 4. +Chatbot: The result of 22 - 7 is 15. +Chatbot: Goodbye! Have a great day!