main.c (3572B)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 | #include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <pthread.h>
#include <sys/stat.h>
#include <wchar.h>
#include <readline/readline.h>
#include <readline/history.h>
#include "defaults.h"
#include "error.h"
#include "parse.h"
#include "execute.h"
#include "displays.h"
#include "gui.h"
static const char *PROMPT = "::> ";
char *response = NULL;
pthread_t thread_id = 0;
void sigint_handle(int sig)
{
printf("\b\b "); // Obsucre '^C' output.
if (thread_id == 0) {
puts("\b\b\033[90m//----\033[0m");
printf("\033[1m");
printf("Signal (%d), [Ctrl-D] to stop inputting.\n", sig);
printf("\033[0m");
rl_on_new_line();
rl_replace_line("", 0);
rl_redisplay();
} else {
pthread_cancel(thread_id);
printf("\b\b\033[1mInterrputed expression evaluation");
printf(" (thread 0x%lX).\033[0m\n", thread_id);
thread_id = 0;
}
}
void *evaluation_thread(void *ctx_void)
{
Context *ctx = ctx_void;
ParseNode *tree = NULL;
DataValue *result = NULL;
tree = parse(response);
if (tree == NULL || ERROR_TYPE != NO_ERROR) {
handle_error();
return (void *)EXIT_FAILURE;
}
printf("\033[%luC\033[1A",
strlen(PROMPT)
+ strlen(response));
printf("\033[2m ≡ %s\033[0m\n", display_parsetree(tree));
result = execute(ctx, tree);
if (result == NULL || ERROR_TYPE != NO_ERROR) {
handle_error();
return (void *)EXIT_FAILURE;
}
if (result != NULL)
printf("#=> %s\n", display_datavalue(result));
if (tree != NULL)
free_parsenode(tree);
return (void *)EXIT_SUCCESS;
}
int main(int argc, char **argv)
{
// Welcome messsage.
printf("\033[1m");
printf("CREPL — Calculator Read Eval Print Loop");
printf("\033[0m");
puts(" (v" VERSION ") (" COMPILER ") (" __DATE__ ")");
bool verbose = false;
bool gui_mode = false;
// Parse command line arguments.
for (int i = 0; i < argc; ++i) {
if (strcmp(argv[i], "-v") == 0
|| strcmp(argv[i], "--verbose") == 0)
verbose = true;
else if (strcmp(argv[i], "-V") == 0
|| strcmp(argv[i], "--version") == 0)
{ puts("Version " VERSION "."); return EXIT_SUCCESS; }
else if (strcmp(argv[i], "-g") == 0
|| strcmp(argv[i], "--gui") == 0)
gui_mode = true;
}
#ifndef GUI
if (gui_mode) {
puts("This CREPL executable was not compiled with GUI support.");
return EXIT_FAILURE;
}
#else
if (gui_mode) {
int success = start_gui();
if (success == 0)
return EXIT_SUCCESS;
return EXIT_FAILURE;
}
#endif
puts("Type \"exit\" or [Ctrl-D] (i.e. EOF) to quit.");
// Configure readline.
rl_clear_signals();
rl_bind_key('\t', rl_insert);
signal(SIGINT, sigint_handle);
// Create or fetch history file.
char cache_loc[128] = "~/.cache/";
char *tmp = NULL;
if ((tmp = getenv("XDG_CACHE_HOME")) != NULL)
strcpy(cache_loc, tmp);
else if ((tmp = getenv("HOME")) != NULL)
sprintf(cache_loc, "%s/.cache", tmp);
mkdir(cache_loc, 0777);
strcat(cache_loc, "/crepl.history");
read_history(cache_loc);
if (verbose) {
printf("Reading history from `%s'.\n", cache_loc);
}
Context *ctx = base_context();
do {
char *line = readline(PROMPT);
if (line == NULL
|| strcmp("exit", downcase(trim(line))) == 0)
break;
if (response == NULL || strcmp(line, response) != 0)
add_history(line);
response = line;
// Evaluation of input is done in thread.
pthread_create(&thread_id, NULL, evaluation_thread, ctx);
pthread_join(thread_id, NULL);
thread_id = 0;
} while (true);
write_history(cache_loc);
printf("\r\033[2K");
printf("Buh-bye.\n");
return EXIT_SUCCESS;
}
|