Compare commits
8 Commits
25f5d3469b
...
3c0648e473
Author | SHA1 | Date |
---|---|---|
Danila Fedorin | 3c0648e473 | |
Danila Fedorin | 8192d767f2 | |
Danila Fedorin | 416686ca72 | |
Danila Fedorin | fdca2a8ca7 | |
Danila Fedorin | d0615d2c3e | |
Danila Fedorin | b1ab168907 | |
Danila Fedorin | 3b79b5751a | |
Danila Fedorin | 7c8c547540 |
|
@ -28,6 +28,14 @@ struct libab_interpreter_s {
|
|||
* The unit value, which doesn't need more than one instance.
|
||||
*/
|
||||
libab_ref value_unit;
|
||||
/**
|
||||
* The "true" boolean value, which doesn't need more than one instance.
|
||||
*/
|
||||
libab_ref value_true;
|
||||
/**
|
||||
* The "false" boolean value, which doesn't need more than one instance.
|
||||
*/
|
||||
libab_ref value_false;
|
||||
};
|
||||
|
||||
typedef enum libab_interpreter_scope_mode_e libab_interpreter_scope_mode;
|
||||
|
@ -73,6 +81,18 @@ libab_result libab_interpreter_run_function(libab_interpreter* intr,
|
|||
* @param into the reference into which to store the unit value.
|
||||
*/
|
||||
void libab_interpreter_unit_value(libab_interpreter* intr, libab_ref* into);
|
||||
/**
|
||||
* Gets the true value from this interpreter.
|
||||
* @param intr the interpreter from which to get the true value.
|
||||
* @param into the reference into which to store the true value.
|
||||
*/
|
||||
void libab_interpreter_true_value(libab_interpreter* intr, libab_ref* into);
|
||||
/**
|
||||
* Gets the false value from this interpreter.
|
||||
* @param intr the interpreter from which to get the false value.
|
||||
* @param into the reference into which to store the false value.
|
||||
*/
|
||||
void libab_interpreter_false_value(libab_interpreter* intr, libab_ref* into);
|
||||
/**
|
||||
* Frees the given interpreter.
|
||||
* @param intr the interpreter to free.
|
||||
|
|
|
@ -60,6 +60,8 @@ enum libab_lexer_token_e {
|
|||
TOKEN_OP_PREFIX,
|
||||
TOKEN_OP_POSTFIX,
|
||||
TOKEN_OP_RESERVED,
|
||||
TOKEN_KW_TRUE,
|
||||
TOKEN_KW_FALSE,
|
||||
TOKEN_KW_IF,
|
||||
TOKEN_KW_ELSE,
|
||||
TOKEN_KW_WHILE,
|
||||
|
|
|
@ -204,6 +204,18 @@ void libab_get_type_unit(libab* ab, libab_ref* into);
|
|||
* @param into the reference into which to store the unit value.
|
||||
*/
|
||||
void libab_get_unit_value(libab* ab, libab_ref* into);
|
||||
/**
|
||||
* Gets the true value form this libab instance.
|
||||
* @param ab the instance to get the true value from.
|
||||
* @param into the reference into which to store the true value.
|
||||
*/
|
||||
void libab_get_true_value(libab* ab, libab_ref* into);
|
||||
/**
|
||||
* Gets the false value form this libab instance.
|
||||
* @param ab the instance to get the false value from.
|
||||
* @param into the reference into which to store the false value.
|
||||
*/
|
||||
void libab_get_false_value(libab* ab, libab_ref* into);
|
||||
|
||||
/**
|
||||
* Executes the given string of code.
|
||||
|
|
|
@ -19,6 +19,8 @@ enum libab_tree_variant_e {
|
|||
TREE_POSTFIX_OP,
|
||||
TREE_BLOCK,
|
||||
TREE_VOID,
|
||||
TREE_TRUE,
|
||||
TREE_FALSE,
|
||||
TREE_IF,
|
||||
TREE_WHILE,
|
||||
TREE_DOWHILE,
|
||||
|
|
|
@ -7,6 +7,10 @@
|
|||
#define TRY(expression) \
|
||||
if (result == LIBAB_SUCCESS) \
|
||||
result = expression;
|
||||
#define FUNCTION(name) \
|
||||
libab_result function_##name (libab* ab, libab_ref* scope, \
|
||||
libab_ref_vec* params, libab_ref* into)
|
||||
|
||||
#define INTERACTIONS 5
|
||||
|
||||
void* impl_parse(const char* string) {
|
||||
|
@ -38,34 +42,59 @@ libab_result create_double_value(libab* ab, double val, libab_ref* into) {
|
|||
return result;
|
||||
}
|
||||
|
||||
libab_result function_atan(libab* ab, libab_ref* scope, libab_ref_vec* params, libab_ref* into) {
|
||||
void get_boolean_value(libab* ab, int val, libab_ref* into) {
|
||||
val ? libab_get_true_value(ab, into) : libab_get_false_value(ab, into);
|
||||
}
|
||||
|
||||
FUNCTION(and) {
|
||||
int* left = libab_unwrap_param(params, 0);
|
||||
int* right = libab_unwrap_param(params, 1);
|
||||
get_boolean_value(ab, *left & *right, into);
|
||||
return LIBAB_SUCCESS;
|
||||
}
|
||||
|
||||
FUNCTION(or) {
|
||||
int* left = libab_unwrap_param(params, 0);
|
||||
int* right = libab_unwrap_param(params, 1);
|
||||
get_boolean_value(ab, *left | *right, into);
|
||||
return LIBAB_SUCCESS;
|
||||
}
|
||||
|
||||
FUNCTION(xor) {
|
||||
int* left = libab_unwrap_param(params, 0);
|
||||
int* right = libab_unwrap_param(params, 1);
|
||||
get_boolean_value(ab, *left ^ *right, into);
|
||||
return LIBAB_SUCCESS;
|
||||
}
|
||||
|
||||
FUNCTION(atan) {
|
||||
printf("atan called\n");
|
||||
double* val = libab_unwrap_param(params, 0);
|
||||
return create_double_value(ab, atan(*val), into);
|
||||
}
|
||||
|
||||
libab_result function_atan2(libab* ab, libab_ref* scope, libab_ref_vec* params, libab_ref* into) {
|
||||
FUNCTION(atan2) {
|
||||
printf("atan2 called\n");
|
||||
double* left = libab_unwrap_param(params, 0);
|
||||
double* right = libab_unwrap_param(params, 1);
|
||||
return create_double_value(ab, atan2(*left, *right), into);
|
||||
}
|
||||
|
||||
libab_result function_print_num(libab* ab, libab_ref* scope, libab_ref_vec* params, libab_ref* into) {
|
||||
FUNCTION(print_num) {
|
||||
double* param = libab_unwrap_param(params, 0);
|
||||
printf("%f\n", *param);
|
||||
libab_get_unit_value(ab, into);
|
||||
return LIBAB_SUCCESS;
|
||||
}
|
||||
|
||||
libab_result function_print_bool(libab* ab, libab_ref* scope, libab_ref_vec* params, libab_ref* into) {
|
||||
FUNCTION(print_bool) {
|
||||
int* param = libab_unwrap_param(params, 0);
|
||||
printf("%s\n", *param ? "true" : "false");
|
||||
libab_get_unit_value(ab, into);
|
||||
return LIBAB_SUCCESS;
|
||||
}
|
||||
|
||||
libab_result function_print_unit(libab* ab, libab_ref* scope, libab_ref_vec* params, libab_ref* into) {
|
||||
FUNCTION(print_unit) {
|
||||
printf("()\n");
|
||||
libab_get_unit_value(ab, into);
|
||||
return LIBAB_SUCCESS;
|
||||
|
@ -96,6 +125,7 @@ libab_result register_functions(libab* ab) {
|
|||
libab_ref print_num_type;
|
||||
libab_ref print_unit_type;
|
||||
libab_ref print_bool_type;
|
||||
libab_ref bool_logic_type;
|
||||
|
||||
result = libab_create_type(ab, &trig_type, "(num)->num");
|
||||
TRY(libab_create_type(ab, &atan2_type, "(num, num)->num"));
|
||||
|
@ -103,6 +133,7 @@ libab_result register_functions(libab* ab) {
|
|||
TRY(libab_create_type(ab, &print_num_type, "(num)->unit"));
|
||||
TRY(libab_create_type(ab, &print_unit_type, "(unit)->unit"));
|
||||
TRY(libab_create_type(ab, &print_bool_type, "(bool)->unit"));
|
||||
TRY(libab_create_type(ab, &bool_logic_type, "(bool,bool)->bool"));
|
||||
|
||||
TRY(libab_register_function(ab, "atan", &trig_type, function_atan));
|
||||
TRY(libab_register_function(ab, "atan2", &atan2_type, function_atan2));
|
||||
|
@ -110,6 +141,9 @@ libab_result register_functions(libab* ab) {
|
|||
TRY(libab_register_function(ab, "minus", &atan2_type, function_minus));
|
||||
TRY(libab_register_function(ab, "times", &atan2_type, function_times));
|
||||
TRY(libab_register_function(ab, "divide", &atan2_type, function_divide));
|
||||
TRY(libab_register_function(ab, "and", &bool_logic_type, function_and));
|
||||
TRY(libab_register_function(ab, "or", &bool_logic_type, function_or));
|
||||
TRY(libab_register_function(ab, "xor", &bool_logic_type, function_xor));
|
||||
TRY(libab_register_function(ab, "print", &print_num_type, function_print_num));
|
||||
TRY(libab_register_function(ab, "print", &print_unit_type, function_print_unit));
|
||||
TRY(libab_register_function(ab, "print", &print_bool_type, function_print_bool));
|
||||
|
@ -117,6 +151,9 @@ libab_result register_functions(libab* ab) {
|
|||
TRY(libab_register_operator_infix(ab, "-", 0, -1, "minus"));
|
||||
TRY(libab_register_operator_infix(ab, "*", 1, -1, "times"));
|
||||
TRY(libab_register_operator_infix(ab, "/", 1, -1, "divide"));
|
||||
TRY(libab_register_operator_infix(ab, "&", 1, -1, "and"));
|
||||
TRY(libab_register_operator_infix(ab, "|", 1, -1, "or"));
|
||||
TRY(libab_register_operator_infix(ab, "^", 1, -1, "xor"));
|
||||
|
||||
libab_ref_free(&trig_type);
|
||||
libab_ref_free(&atan2_type);
|
||||
|
@ -144,6 +181,10 @@ libab_result loop(libab* ab, int interaction_count, libab_ref* scope) {
|
|||
printf("Invalid input (error code %d).\n", eval_result);
|
||||
} else {
|
||||
result = libab_run_function_scoped(ab, "print", scope, &call_into, 1, &eval_into);
|
||||
if(result == LIBAB_BAD_CALL) {
|
||||
printf("(?)\n");
|
||||
result = LIBAB_SUCCESS;
|
||||
}
|
||||
libab_ref_free(&call_into);
|
||||
}
|
||||
libab_ref_free(&eval_into);
|
||||
|
|
|
@ -4,15 +4,52 @@
|
|||
#include "free_functions.h"
|
||||
#include "reserved.h"
|
||||
|
||||
libab_result _create_bool_value(libab* ab, int val, libab_ref* into) {
|
||||
libab_ref type_bool;
|
||||
int* new_bool;
|
||||
libab_result result = LIBAB_SUCCESS;
|
||||
|
||||
libab_get_type_bool(ab, &type_bool);
|
||||
new_bool = malloc(sizeof(*new_bool));
|
||||
if(new_bool) {
|
||||
*new_bool = val;
|
||||
result = libab_create_value_raw(into, new_bool, &type_bool);
|
||||
if(result != LIBAB_SUCCESS) {
|
||||
free(new_bool);
|
||||
}
|
||||
} else {
|
||||
result = LIBAB_MALLOC;
|
||||
libab_ref_null(into);
|
||||
}
|
||||
libab_ref_free(&type_bool);
|
||||
return result;
|
||||
}
|
||||
|
||||
libab_result libab_interpreter_init(libab_interpreter* intr, libab* ab) {
|
||||
libab_result result;
|
||||
libab_ref unit_data;
|
||||
intr->ab = ab;
|
||||
libab_ref_null(&intr->value_true);
|
||||
libab_ref_null(&intr->value_false);
|
||||
|
||||
libab_ref_null(&unit_data);
|
||||
result = libab_create_value_ref(&intr->value_unit, &unit_data, &ab->type_unit);
|
||||
if(result == LIBAB_SUCCESS) {
|
||||
libab_ref_free(&intr->value_true);
|
||||
result = _create_bool_value(ab, 1, &intr->value_true);
|
||||
}
|
||||
if(result == LIBAB_SUCCESS) {
|
||||
libab_ref_free(&intr->value_false);
|
||||
result = _create_bool_value(ab, 0, &intr->value_false);
|
||||
}
|
||||
libab_ref_free(&unit_data);
|
||||
|
||||
if(result != LIBAB_SUCCESS) {
|
||||
libab_ref_free(&intr->value_unit);
|
||||
libab_ref_free(&intr->value_true);
|
||||
libab_ref_free(&intr->value_false);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -1171,6 +1208,32 @@ libab_result _interpreter_run(struct interpreter_state* state, libab_tree* tree,
|
|||
vec_index(&tree->children, 0),
|
||||
vec_index(&tree->children, 1),
|
||||
into);
|
||||
} else if(tree->variant == TREE_TRUE) {
|
||||
libab_get_true_value(state->ab, into);
|
||||
} else if(tree->variant == TREE_FALSE) {
|
||||
libab_get_false_value(state->ab, into);
|
||||
} else if (tree->variant == TREE_IF) {
|
||||
libab_ref condition;
|
||||
libab_value* condition_value;
|
||||
libab_parsetype* condition_type;
|
||||
result = _interpreter_run(state, vec_index(&tree->children, 0),
|
||||
&condition, scope, SCOPE_NORMAL);
|
||||
|
||||
if(result == LIBAB_SUCCESS) {
|
||||
condition_value = libab_ref_get(&condition);
|
||||
condition_type = libab_ref_get(&condition_value->type);
|
||||
if(condition_type->data_u.base != libab_get_basetype_bool(state->ab)) {
|
||||
result = LIBAB_MISMATCHED_TYPE;
|
||||
}
|
||||
}
|
||||
|
||||
if(result == LIBAB_SUCCESS) {
|
||||
int* boolean = libab_ref_get(&condition_value->data);
|
||||
result = _interpreter_run(state, vec_index(&tree->children,
|
||||
*boolean ? 1 : 2), into, scope, SCOPE_NORMAL);
|
||||
}
|
||||
|
||||
libab_ref_free(&condition);
|
||||
} else {
|
||||
libab_get_unit_value(state->ab, into);
|
||||
}
|
||||
|
@ -1225,6 +1288,16 @@ void libab_interpreter_unit_value(libab_interpreter* intr, libab_ref* into) {
|
|||
libab_ref_copy(&intr->value_unit, into);
|
||||
}
|
||||
|
||||
void libab_interpreter_true_value(libab_interpreter* intr, libab_ref* into) {
|
||||
libab_ref_copy(&intr->value_true, into);
|
||||
}
|
||||
|
||||
void libab_interpreter_false_value(libab_interpreter* intr, libab_ref* into) {
|
||||
libab_ref_copy(&intr->value_false, into);
|
||||
}
|
||||
|
||||
void libab_interpreter_free(libab_interpreter* intr) {
|
||||
libab_ref_free(&intr->value_unit);
|
||||
libab_ref_free(&intr->value_true);
|
||||
libab_ref_free(&intr->value_false);
|
||||
}
|
||||
|
|
|
@ -10,6 +10,8 @@ libab_result libab_lexer_init(libab_lexer* lexer) {
|
|||
const char* words[] = {".",
|
||||
"[a-zA-Z][a-zA-Z0-9_]*",
|
||||
"[0-9]+(\\.[0-9]*)?",
|
||||
"true",
|
||||
"false",
|
||||
"if",
|
||||
"else",
|
||||
"while",
|
||||
|
@ -18,9 +20,9 @@ libab_result libab_lexer_init(libab_lexer* lexer) {
|
|||
"fun",
|
||||
"return"};
|
||||
libab_lexer_token tokens[] = {
|
||||
TOKEN_CHAR, TOKEN_ID, TOKEN_NUM, TOKEN_KW_IF,
|
||||
TOKEN_KW_ELSE, TOKEN_KW_WHILE, TOKEN_KW_DO, TOKEN_KW_ARROW,
|
||||
TOKEN_KW_FUN, TOKEN_KW_RETURN };
|
||||
TOKEN_CHAR, TOKEN_ID, TOKEN_NUM, TOKEN_KW_TRUE,
|
||||
TOKEN_KW_FALSE, TOKEN_KW_IF, TOKEN_KW_ELSE, TOKEN_KW_WHILE,
|
||||
TOKEN_KW_DO, TOKEN_KW_ARROW, TOKEN_KW_FUN, TOKEN_KW_RETURN};
|
||||
const size_t count = sizeof(tokens) / sizeof(libab_lexer_token);
|
||||
|
||||
eval_config_init(&lexer->config);
|
||||
|
|
|
@ -87,7 +87,9 @@ libab_result libab_init(libab* ab, void* (*parse_function)(const char*),
|
|||
void _sanitize(char* to, const char* from, size_t buffer_size) {
|
||||
size_t index = 0;
|
||||
while (*from && index < (buffer_size - 2)) {
|
||||
if (*from == '+' || *from == '*' || *from == '\\')
|
||||
if (*from == '+' || *from == '*' || *from == '\\' ||
|
||||
*from == '|' || *from == '[' || *from == ']' || *from == '(' ||
|
||||
*from == ')')
|
||||
to[index++] = '\\';
|
||||
to[index++] = *(from++);
|
||||
}
|
||||
|
@ -402,6 +404,14 @@ void libab_get_unit_value(libab* ab, libab_ref* into) {
|
|||
libab_interpreter_unit_value(&ab->intr, into);
|
||||
}
|
||||
|
||||
void libab_get_true_value(libab* ab, libab_ref* into) {
|
||||
libab_interpreter_true_value(&ab->intr, into);
|
||||
}
|
||||
|
||||
void libab_get_false_value(libab* ab, libab_ref* into) {
|
||||
libab_interpreter_false_value(&ab->intr, into);
|
||||
}
|
||||
|
||||
libab_result _create_tree(libab* ab, const char* string, libab_tree** into) {
|
||||
libab_result result = LIBAB_SUCCESS;
|
||||
ll tokens;
|
||||
|
|
46
src/parser.c
46
src/parser.c
|
@ -406,6 +406,38 @@ libab_result _parse_void(struct parser_state* state, libab_tree** store_into) {
|
|||
return result;
|
||||
}
|
||||
|
||||
libab_result _parse_true(struct parser_state* state, libab_tree** store_into) {
|
||||
libab_result result = _parser_consume_type(state, TOKEN_KW_TRUE);
|
||||
if(result == LIBAB_SUCCESS) {
|
||||
if ((*store_into = malloc(sizeof(**store_into)))) {
|
||||
(*store_into)->variant = TREE_TRUE;
|
||||
} else {
|
||||
result = LIBAB_MALLOC;
|
||||
}
|
||||
}
|
||||
|
||||
if(result != LIBAB_SUCCESS) {
|
||||
*store_into = NULL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
libab_result _parse_false(struct parser_state* state, libab_tree** store_into) {
|
||||
libab_result result = _parser_consume_type(state, TOKEN_KW_FALSE);
|
||||
if(result == LIBAB_SUCCESS) {
|
||||
if ((*store_into = malloc(sizeof(**store_into)))) {
|
||||
(*store_into)->variant = TREE_FALSE;
|
||||
} else {
|
||||
result = LIBAB_MALLOC;
|
||||
}
|
||||
}
|
||||
|
||||
if(result != LIBAB_SUCCESS) {
|
||||
*store_into = NULL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
libab_result _parse_if(struct parser_state* state, libab_tree** store_into) {
|
||||
libab_result result = LIBAB_SUCCESS;
|
||||
libab_tree* condition = NULL;
|
||||
|
@ -736,6 +768,10 @@ libab_result _parse_atom(struct parser_state* state, libab_tree** store_into) {
|
|||
result = _parse_fun(state, store_into);
|
||||
} else if (_parser_is_type(state, TOKEN_KW_RETURN)) {
|
||||
result = _parse_return(state, store_into);
|
||||
} else if (_parser_is_type(state, TOKEN_KW_TRUE)) {
|
||||
result = _parse_true(state, store_into);
|
||||
} else if (_parser_is_type(state, TOKEN_KW_FALSE)) {
|
||||
result = _parse_false(state, store_into);
|
||||
} else {
|
||||
result = LIBAB_UNEXPECTED;
|
||||
}
|
||||
|
@ -1019,11 +1055,13 @@ libab_result _parse_expression(struct parser_state* state,
|
|||
|
||||
while (result == LIBAB_SUCCESS && op_stack.tail &&
|
||||
_parser_match_is_op(op_stack.tail->data)) {
|
||||
_parser_find_operator_infix(state, op_stack.tail->data,
|
||||
&other_operator);
|
||||
libab_lexer_match* other_token = op_stack.tail->data;
|
||||
if(other_token->type == TOKEN_OP_INFIX) {
|
||||
_parser_find_operator_infix(state, op_stack.tail->data,
|
||||
&other_operator);
|
||||
}
|
||||
|
||||
if (((libab_lexer_match*)op_stack.tail->data)->type ==
|
||||
TOKEN_OP_PREFIX ||
|
||||
if (other_token->type == TOKEN_OP_PREFIX ||
|
||||
(operator.associativity == - 1 &&
|
||||
operator.precedence <= other_operator.precedence) ||
|
||||
(operator.associativity == 1 &&
|
||||
|
|
Loading…
Reference in New Issue