commit 2371441cbf6ff1ee4ebbbcece350721798bb8b57
parent 544607481e0d7f0a5b595fd4c30d0481e46a446b
Author: Demonstrandum <moi@knutsen.co>
Date: Mon, 17 Aug 2020 01:37:37 +0100
Ability to cancel execution.
Diffstat:
7 files changed, 107 insertions(+), 46 deletions(-)
diff --git a/Makefile b/Makefile
@@ -1,7 +1,7 @@
CC := gcc
OPT := -O3
-WARN := -Wall -Wpedantic -Wextra -Wshadow -fcompare-debug-second
-LINKS := -lm -lreadline
+WARN := -Wall -Wpedantic -Wextra -Wshadow -Wno-psabi
+LINKS := -lm -lreadline -lpthread
CFLAGS := $(WARN) $(OPT)
TARGET := crepl
OBJS := main.o defaults.o error.o parse.o displays.o builtin.o execute.o prelude.o
diff --git a/src/builtin.c b/src/builtin.c
@@ -76,6 +76,19 @@ NumberNode *upcast_pair(NumberNode lhs, NumberNode rhs)
return pair;
}
+DataValue *builtin_sleep(DataValue seconds)
+{
+ NumberNode *num = type_check("sleep", ARG, T_NUMBER, &seconds);
+ if (num == NULL) return NULL;
+
+ NumberNode *time = malloc(sizeof(NumberNode));
+ *time = num_to_int(*num);
+ if (time->value.i < 0) time->value.i = 0;
+
+ sleep((unsigned)time->value.i);
+ return wrap_data(T_NUMBER, time);
+}
+
#define MATH_WRAPPER(NAME, FUNC)\
DataValue *builtin_ ##NAME (DataValue input) \
{ \
diff --git a/src/builtin.h b/src/builtin.h
@@ -1,6 +1,7 @@
#pragma once
#include <math.h>
+#include <unistd.h>
#include "defaults.h"
#include "parse.h"
@@ -13,6 +14,7 @@ NumberNode *upcast_pair(NumberNode, NumberNode);
fsize gamma_func(float, fsize);
fsize gammae(fsize);
+DataValue *builtin_sleep(DataValue);
DataValue *builtin_sin(DataValue);
DataValue *builtin_sinh(DataValue);
DataValue *builtin_cos(DataValue);
@@ -52,6 +54,7 @@ struct _func_name_pair {
};
static const struct _func_name_pair builtin_fns[] = {
+ FUNC_PAIR(sleep),
FUNC_PAIR(sin),
FUNC_PAIR(sinh),
FUNC_PAIR(cos),
diff --git a/src/defaults.c b/src/defaults.c
@@ -15,7 +15,20 @@ ssize ipow(ssize base, usize exp)
return result;
}
-char *trim(char *str)
+char *remove_all_char(const char *str, char chr)
+{
+ char *new = strdup(str);
+ size_t str_len = strlen(str);
+ size_t new_len = 0;
+
+ for (size_t i = 0; i < str_len; ++i)
+ if (str[i] != chr) new[new_len++] = str[i];
+
+ new[new_len] = '\0';
+ return new;
+}
+
+char *trim(const char *str)
{
char *p = strdup(str);
while (isspace(*p))
@@ -30,7 +43,7 @@ char *trim(char *str)
}
-char *downcase(char *str)
+char *downcase(const char *str)
{
char *p = strdup(str);
char *start = p;
diff --git a/src/defaults.h b/src/defaults.h
@@ -38,8 +38,9 @@ typedef long double fsize;
ssize ipow(ssize, usize);
-char *trim(char *);
-char *downcase(char *);
+char *remove_all_char(const char *, char);
+char *trim(const char *);
+char *downcase(const char *);
#define STR_HELPER(x) #x
#define STR(x) STR_HELPER(x)
diff --git a/src/main.c b/src/main.c
@@ -1,7 +1,9 @@
#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>
@@ -16,13 +18,61 @@
static const char *PROMPT = "::> ";
+char *response = NULL;
+pthread_t thread_id = 0;
+
void sigint_handle(int sig)
{
printf("\b\b "); // Obsucre '^C' output.
- printf("\nInterrupted (%d), [Ctrl-D] to stop inputting.\n", sig);
- rl_on_new_line();
- rl_replace_line("", 0);
- rl_redisplay();
+ 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)
@@ -65,7 +115,6 @@ int main(int argc, char **argv)
Context *ctx = base_context();
- char *response = NULL;
do {
char *line = readline(PROMPT);
@@ -77,29 +126,10 @@ int main(int argc, char **argv)
add_history(line);
response = line;
- // Try to lex & parse the input.
- ParseNode *tree = parse(response);
-
- if (tree == NULL || ERROR_TYPE != NO_ERROR) {
- handle_error();
- continue;
- }
-
- printf("\033[%luC\033[1A",
- strlen(PROMPT)
- + strlen(response));
- printf("\033[2m ≡ %s\033[0m\n", display_parsetree(tree));
-
- DataValue *result = execute(ctx, tree);
-
- if (result == NULL || ERROR_TYPE != NO_ERROR) {
- handle_error();
- continue;
- }
-
- printf("#=> %s\n", display_datavalue(result));
-
- free_parsenode(tree);
+ // 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);
diff --git a/src/parse.c b/src/parse.c
@@ -49,23 +49,22 @@ TokenType char_token_type(char c, char last_char, TokenType last_token_type)
if (c <= '9' && c >= '0') {
if (last_token_type == TT_IDENTIFIER)
return TT_IDENTIFIER;
- else
- return TT_NUMERIC;
+ return TT_NUMERIC;
}
if (c == '_'
- && (last_token_type == TT_IDENTIFIER
+ && (last_token_type == TT_IDENTIFIER
|| last_token_type == TT_NUMERIC))
return last_token_type;
if (c == '.'
&& (last_token_type == TT_OPERATOR
|| last_token_type == TT_NONE))
return TT_NUMERIC;
- if ((c == '.' || c == 'E') // Scientific notation.
+ if ((c == '.' || c == 'E' || c == 'P') // Scientific notation.
&& last_token_type == TT_NUMERIC)
return TT_NUMERIC;
if ((c == '+' || c == '-') && last_char == 'E')
return TT_NUMERIC;
- if ((c == 'x' || c == 'o') && last_char == '0')
+ if ((c == 'x' || c == 'X' || c == 'o' || c == 'O') && last_char == '0')
return TT_NUMERIC;
if (c == '(')
return TT_LPAREN;
@@ -75,12 +74,11 @@ TokenType char_token_type(char c, char last_char, TokenType last_token_type)
return TT_NONE;
// All possible operator/special-symbol characters:
- if ((c >= '!' && c <= '/')
- || (c >= ':' && c <= '@')
- || (c >= '{' && c <= '~')
- || (c >= '[' && c <= '`')) {
- return TT_OPERATOR;
- }
+ if (((c >= '!' && c <= '/')
+ || (c >= ':' && c <= '@')
+ || (c >= '{' && c <= '~')
+ || (c >= '[' && c <= '`'))
+ && c != '_') return TT_OPERATOR;
// Anything else is treated as an identifier.
return TT_IDENTIFIER;
@@ -200,11 +198,14 @@ NumberNode *make_number(NumberType type, void *val)
// Parse number literals:
// e.g. 3, 8.2, 2E32, 3E+4, 1.6E-19, 0b010110, 0xff32a1, 0o0774, etc.
-// TODO: Parse binary, hexadecimal and octal literals (0b, 0x, 0o).
+// TODO: Parse binary, hexadecimal and octal literals (0b, 0x, 0o)
+// as well as hex/binary `P' power notation..
NumberNode *parse_number(const char *str)
{
NumberNode *number = malloc(sizeof(NumberNode));
+ str = remove_all_char(str, '_');
+
char *exponent_ptr = strstr(str, "E");
char *neg_exponent_ptr = strstr(str, "E-");
char *decimal_point_ptr = strstr(str, ".");