diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | src/mds-kbdc/builtin-functions.c | 55 | ||||
-rw-r--r-- | src/mds-kbdc/builtin-functions.h | 4 | ||||
-rw-r--r-- | src/mds-kbdc/compile-layout.c | 73 | ||||
-rw-r--r-- | src/mds-kbdc/include-stack.c | 4 | ||||
-rw-r--r-- | src/mds-kbdc/include-stack.h | 2 | ||||
-rw-r--r-- | src/mds-kbdc/tree.c | 16 | ||||
-rw-r--r-- | src/mds-kbdc/tree.h | 4 | ||||
-rw-r--r-- | src/mds-kbdc/variables.c | 197 | ||||
-rw-r--r-- | src/mds-kbdc/variables.h | 80 |
10 files changed, 393 insertions, 44 deletions
@@ -33,7 +33,7 @@ OBJ_mds-registry_ = mds-registry util globals reexec registry signals \ OBJ_mds-kbdc_ = mds-kbdc globals raw-data builtin-functions string \ tree make-tree parse-error simplify-tree parsed \ process-includes validate-tree eliminate-dead-code \ - paths include-stack compile-layout + paths include-stack compile-layout variables OBJ_mds-server = $(foreach O,$(OBJ_mds-server_),obj/mds-server/$(O).o) OBJ_mds-registry = $(foreach O,$(OBJ_mds-registry_),obj/mds-registry/$(O).o) diff --git a/src/mds-kbdc/builtin-functions.c b/src/mds-kbdc/builtin-functions.c index cfac8ac..0cb7aa6 100644 --- a/src/mds-kbdc/builtin-functions.c +++ b/src/mds-kbdc/builtin-functions.c @@ -17,6 +17,8 @@ */ #include "builtin-functions.h" +#include "variables.h" + #include <stdlib.h> #include <string.h> @@ -258,8 +260,45 @@ static char32_t* builtin_function_less_2(const char32_t** restrict args) } -/* static char32_t* builtin_function_set_3(const char32_t** restrict args); (variable index value) */ -/* static char32_t* builtin_function_get_2(const char32_t** restrict args); (variable index) */ +/** + * Definition of the built-in function get/2 + * + * @param args The arguments passed to the function + * @return The return value of the function, `NULL` on error + */ +static char32_t* builtin_function_get_2(const char32_t** restrict args) +{ + const char32_t* restrict a = *args++; + const char32_t* restrict b = *args++; + size_t n = (size_t)*b; + mds_kbdc_tree_t* value = variables_get((size_t)*a); + while (n--) + value = value->next; + return string_dup(value->compiled_string.string); +} + + +/** + * Definition of the built-in function set/3 + * + * @param args The arguments passed to the function + * @return The return value of the function, `NULL` on error + */ +static char32_t* builtin_function_set_3(const char32_t** restrict args) +{ + const char32_t* restrict a = *args++; + const char32_t* restrict b = *args++; + const char32_t* restrict c = *args++; + size_t n = (size_t)*b; + mds_kbdc_tree_t* value = variables_get((size_t)*a); + while (n--) + value = value->next; + free(value->compiled_string.string); + value->compiled_string.string = string_dup(c); + if (value->compiled_string.string == NULL) + return NULL; + return string_dup(c); +} #undef define_1 @@ -298,6 +337,10 @@ int builtin_function_defined(const char* restrict name, size_t arg_count) /** * Invoke a builtin function * + * The function will abort if an non-builtin function is addressed + * + * Before invoking set/3 or get/2, please check the arguments + * * @param name The name of the function * @param arg_count The number of arguments to pass to the function * @param args The arguments to pass @@ -307,14 +350,14 @@ char32_t* builtin_function_invoke(const char* restrict name, size_t arg_count, c { if (arg_count == 3) if (!strcmp(name, "set")) - return NULL; /* TODO builtin_function_set_3(args) */ + return builtin_function_set_3(args); if (arg_count == 1) if (!strcmp(name, "not")) return builtin_function_not_1(args); if (arg_count != 2) - return NULL; + abort(); if (!strcmp(name, "add")) return builtin_function_add_2(args); if (!strcmp(name, "sub")) return builtin_function_sub_2(args); @@ -329,8 +372,8 @@ char32_t* builtin_function_invoke(const char* restrict name, size_t arg_count, c if (!strcmp(name, "equals")) return builtin_function_equals_2(args); if (!strcmp(name, "greater")) return builtin_function_greater_2(args); if (!strcmp(name, "less")) return builtin_function_less_2(args); - if (!strcmp(name, "get")) return NULL; /* TODO builtin_function_get_2(args) */ + if (!strcmp(name, "get")) return builtin_function_get_2(args); - return NULL; + abort(); } diff --git a/src/mds-kbdc/builtin-functions.h b/src/mds-kbdc/builtin-functions.h index ebe3935..5c78f0e 100644 --- a/src/mds-kbdc/builtin-functions.h +++ b/src/mds-kbdc/builtin-functions.h @@ -38,6 +38,10 @@ int builtin_function_defined(const char* restrict name, size_t arg_count) __attr /** * Invoke a builtin function * + * The function will abort if an non-builtin function is addressed + * + * Before invoking set/3 or get/2, please check the arguments + * * @param name The name of the function * @param arg_count The number of arguments to pass to the function * @param args The arguments to pass diff --git a/src/mds-kbdc/compile-layout.c b/src/mds-kbdc/compile-layout.c index cdf8df6..3239482 100644 --- a/src/mds-kbdc/compile-layout.c +++ b/src/mds-kbdc/compile-layout.c @@ -21,6 +21,7 @@ #include "include-stack.h" #include "builtin-functions.h" #include "string.h" +#include "variables.h" #include <stdlib.h> #include <errno.h> @@ -144,27 +145,53 @@ static size_t parse_variable(mds_kbdc_tree_t* restrict tree, const char* restric return 0; /* TODO */ } + +/** + * Assign a value to a variable, and define or shadow it in the process + * + * @param variable The variable index + * @param string The variable's new value, must be `NULL` iff `value != NULL` + * @param value The variable's new value, must be `NULL` iff `string != NULL` + * @param statement The statement where the variable is assigned, may be `NULL` + * @param lineoff The offset of the line for where the string selecting the variable begins + * @param possibile_shadow_attempt Whether `statement` is of a type that does not shadow variables, + * but could easily be mistaked for one that does + * @return Zero on success, -1 on error + */ static int let(size_t variable, const char32_t* restrict string, const mds_kbdc_tree_t* restrict value, mds_kbdc_tree_t* restrict statement, size_t lineoff, int possibile_shadow_attempt) { - (void) variable; - (void) string; - (void) value; - (void) statement; - (void) lineoff; - (void) possibile_shadow_attempt; - return 0; /* TODO */ -} - -static int push_stack(void) -{ - return 0; /* TODO */ + mds_kbdc_tree_t* tree = NULL; + int saved_errno; + + /* Warn if this is a possible shadow attempt. */ + if (possibile_shadow_attempt && variables_let_will_override(variable) && + statement && (statement->processed != PROCESS_LEVEL)) + { + statement->processed = PROCESS_LEVEL; + NEW_ERROR(statement, WARNING, "will not shadow existing definition"); + error->start = lineoff; + error->end = lineoff + (size_t)snprintf(NULL, 0, "\\%zu", variable); + } + + /* Duplicate value. */ + if (value) + fail_if ((tree = mds_kbdc_tree_dup(value), tree == NULL)); + if (value == NULL) + { + fail_if ((tree = mds_kbdc_tree_create(C(COMPILED_STRING)), tree == NULL)); + tree->compiled_string.string = string_dup(string); + fail_if (tree->compiled_string.string == NULL); + } + + /* Assign variable. */ + fail_if (variables_let(variable, tree)); + return 0; + FAIL_BEGIN; + mds_kbdc_tree_free(tree); + FAIL_END; } -static int pop_stack(void) -{ - return 0; /* TODO */ -} static int set_macro(const mds_kbdc_tree_macro_t* restrict macro, mds_kbdc_include_stack_t* macro_include_stack) @@ -1072,7 +1099,7 @@ static int compile_let(mds_kbdc_tree_let_t* restrict tree) /* Set the value of the variable. */ fail_if (let(variable, NULL, value, NULL, 0, 0)); - free(value); + mds_kbdc_tree_free(value); return 0; FAIL_BEGIN; free(value); @@ -1339,7 +1366,7 @@ static int compile_macro_call(mds_kbdc_tree_macro_call_t* restrict tree) /* Push call stack and set parameters. */ - fail_if (push_stack()); + variables_stack_push(); for (arg_ = arg; arg_; arg_ = arg_->next) fail_if (let(variable, NULL, arg_, NULL, 0, 0)); @@ -1355,7 +1382,7 @@ static int compile_macro_call(mds_kbdc_tree_macro_call_t* restrict tree) mds_kbdc_include_stack_free(our_include_stack), our_include_stack = NULL; /* Pop call stack. */ - fail_if (pop_stack()); + variables_stack_pop(); done: @@ -1446,10 +1473,14 @@ static int compile_subtree(mds_kbdc_tree_t* restrict tree) */ int compile_layout(mds_kbdc_parsed_t* restrict result_) { - int r; + int r, saved_errno; mds_kbdc_include_stack_begin(result = result_); r = compile_subtree(result_->tree); - return mds_kbdc_include_stack_end(), r; + saved_errno = errno; + mds_kbdc_include_stack_end(); + variables_terminate(); + errno = saved_errno; + return r; } diff --git a/src/mds-kbdc/include-stack.c b/src/mds-kbdc/include-stack.c index dd2bc98..d86374e 100644 --- a/src/mds-kbdc/include-stack.c +++ b/src/mds-kbdc/include-stack.c @@ -109,18 +109,14 @@ void mds_kbdc_include_stack_begin(mds_kbdc_parsed_t* restrict result_) /** * Mark the root of the tree as no longer being visited, * and release clean up after the use of this module - * - * This function is guaranteed not to modify `errno` */ void mds_kbdc_include_stack_end(void) { - int saved_errno = errno; latest_save = NULL; result->pathname = original_pathname; result->source_code = original_source_code; free(includes), includes = NULL; includes_size = includes_ptr = 0; - errno = saved_errno; } diff --git a/src/mds-kbdc/include-stack.h b/src/mds-kbdc/include-stack.h index 49a6248..5d51a61 100644 --- a/src/mds-kbdc/include-stack.h +++ b/src/mds-kbdc/include-stack.h @@ -112,8 +112,6 @@ void mds_kbdc_include_stack_begin(mds_kbdc_parsed_t* restrict result); /** * Mark the root of the tree as no longer being visited, * and release clean up after the use of this module - * - * This function is guaranteed not to modify `errno` */ void mds_kbdc_include_stack_end(void); diff --git a/src/mds-kbdc/tree.c b/src/mds-kbdc/tree.c index 7493ceb..e5af0b9 100644 --- a/src/mds-kbdc/tree.c +++ b/src/mds-kbdc/tree.c @@ -277,9 +277,9 @@ void mds_kbdc_tree_free(mds_kbdc_tree_t* restrict this) * * @param LOWERCASE:identifer The name of subtype */ -#define NODE(LOWERCASE) \ - mds_kbdc_tree_##LOWERCASE##_t* n = (mds_kbdc_tree_##LOWERCASE##_t*)node; \ - mds_kbdc_tree_##LOWERCASE##_t* t = (mds_kbdc_tree_##LOWERCASE##_t*)this +#define NODE(LOWERCASE) \ + mds_kbdc_tree_##LOWERCASE##_t* n = (mds_kbdc_tree_##LOWERCASE##_t*)node; \ + const mds_kbdc_tree_##LOWERCASE##_t* t = (const mds_kbdc_tree_##LOWERCASE##_t*)this /** @@ -288,7 +288,7 @@ void mds_kbdc_tree_free(mds_kbdc_tree_t* restrict this) * @param this The tree node * @return A duplicate of `this`, `NULL` on error */ -mds_kbdc_tree_t* mds_kbdc_tree_dup(mds_kbdc_tree_t* restrict this) +mds_kbdc_tree_t* mds_kbdc_tree_dup(const mds_kbdc_tree_t* restrict this) { mds_kbdc_tree_t* node = NULL; int saved_errno; @@ -357,8 +357,8 @@ mds_kbdc_tree_t* mds_kbdc_tree_dup(mds_kbdc_tree_t* restrict this) * @param NOTATION:const char* The notation for the subtype */ #define NODE(LOWERCASE, NOTATION) \ - mds_kbdc_tree_##LOWERCASE##_t* node; \ - node = (mds_kbdc_tree_##LOWERCASE##_t*)this; \ + const mds_kbdc_tree_##LOWERCASE##_t* node; \ + node = (const mds_kbdc_tree_##LOWERCASE##_t*)this; \ fprintf(output, "%*.s(\033[01m%s\033[00m", indent, "", NOTATION); \ fprintf(output, " \033[36m(@ %zu %zu-%zu)\033[00m", \ node->loc_line + 1, node->loc_start, node->loc_end) @@ -502,7 +502,7 @@ mds_kbdc_tree_t* mds_kbdc_tree_dup(mds_kbdc_tree_t* restrict this) * @param output The output file * @param indent The indent */ -static void mds_kbdc_tree_print_indented(mds_kbdc_tree_t* restrict this, FILE* output, int indent) +static void mds_kbdc_tree_print_indented(const mds_kbdc_tree_t* restrict this, FILE* output, int indent) { again: if (this == NULL) @@ -605,7 +605,7 @@ static void mds_kbdc_tree_print_indented(mds_kbdc_tree_t* restrict this, FILE* o * @param this The tree node * @param output The output file */ -void mds_kbdc_tree_print(mds_kbdc_tree_t* restrict this, FILE* output) +void mds_kbdc_tree_print(const mds_kbdc_tree_t* restrict this, FILE* output) { mds_kbdc_tree_print_indented(this, output, 0); } diff --git a/src/mds-kbdc/tree.h b/src/mds-kbdc/tree.h index 1c5d8d3..885839a 100644 --- a/src/mds-kbdc/tree.h +++ b/src/mds-kbdc/tree.h @@ -831,7 +831,7 @@ void mds_kbdc_tree_free(mds_kbdc_tree_t* restrict this); * @param this The tree node * @return A duplicate of `this`, `NULL` on error */ -mds_kbdc_tree_t* mds_kbdc_tree_dup(mds_kbdc_tree_t* restrict this); +mds_kbdc_tree_t* mds_kbdc_tree_dup(const mds_kbdc_tree_t* restrict this); /** @@ -840,7 +840,7 @@ mds_kbdc_tree_t* mds_kbdc_tree_dup(mds_kbdc_tree_t* restrict this); * @param this The tree node * @param output The output file */ -void mds_kbdc_tree_print(mds_kbdc_tree_t* restrict this, FILE* output); +void mds_kbdc_tree_print(const mds_kbdc_tree_t* restrict this, FILE* output); diff --git a/src/mds-kbdc/variables.c b/src/mds-kbdc/variables.c new file mode 100644 index 0000000..b53569a --- /dev/null +++ b/src/mds-kbdc/variables.c @@ -0,0 +1,197 @@ +/** + * mds — A micro-display server + * Copyright © 2014 Mattias Andrée (maandree@member.fsf.org) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#include "variables.h" + +#include <stdlib.h> +#include <string.h> + + + +/** + * The state of a variable + */ +typedef struct variable +{ + /** + * The current value of the variable + */ + mds_kbdc_tree_t* value; + + /** + * The previous version of variable, + * before it was shadowed + */ + struct variable* restrict previous; + + /** + * The original scope the current shadow + * of the variable was created in + */ + size_t scope; + +} variable_t; + + + +/** + * Map (by index) of defined variables + */ +static variable_t** restrict variables = NULL; + +/** + * The size of `variables` + */ +static size_t variable_count = 0; + +/** + * The current scope, the number of + * times the variable-stakc has been + * pushed without being popped + */ +static size_t current_scope = 0; + + + +/** + * Destroy the variable storage + */ +void variables_terminate(void) +{ + size_t i; + variable_t* old; + for (i = 0; i < variable_count; i++) + while (variables[i]) + { + old = variables[i]; + variables[i] = variables[i]->previous; + mds_kbdc_tree_free(old->value); + free(old); + } + free(variables), variables = NULL; + variable_count = current_scope = 0; +} + + +/** + * Push the variable-stack, making it + * possible to shadow all variables + */ +void variables_stack_push(void) +{ + current_scope++; +} + + +/** + * Undo the actions of `variables_stack_push` + * and all additions to the variable storage + * since it was last called (without a + * corresponding call to this function) + */ +void variables_stack_pop(void) +{ + size_t i; + variable_t* old; + for (i = 0; i < variable_count; i++) + if (variables[i] && (variables[i]->scope == current_scope)) + { + old = variables[i]; + variables[i] = variables[i]->previous; + mds_kbdc_tree_free(old->value); + free(old); + } + current_scope--; +} + + +/** + * Check whether a let will override a variable + * rather the define or shadow it + * + * @param variable The variable index + * @return Whether a let will override the variable + */ +int variables_let_will_override(size_t variable) +{ + if (variable >= variable_count) return 0; + if (variables[variable] == NULL) return 0; + return variables[variable]->scope == current_scope; +} + + +/** + * Assign a value to a variable, and define or shadow it in the process + * + * @param variable The variable index + * @param value The variable's new value + * @return Zero on success, -1 on error + */ +int variables_let(size_t variable, mds_kbdc_tree_t* restrict value) +{ + variable_t** new; + variable_t* previous; + + /* Grow the table if necessary to fit the variable. */ + if (variable >= variable_count) + { + new = realloc(variables, (variable + 1) * sizeof(variable_t*)); + if (new == NULL) + return -1; + variables = new; + memset(variables, 0, (variable + 1 - variable_count) * sizeof(variable_t*)); + variable_count = variable + 1; + } + + if (variables_let_will_override(variable)) + { + /* Override. */ + mds_kbdc_tree_free(variables[variable]->value); + variables[variable]->value = value; + } + else + { + /* Shadow or define. */ + previous = variables[variable]; + variables[variable] = malloc(sizeof(variable_t)); + if (variables[variable] == NULL) + return variables[variable] = previous, -1; + variables[variable]->value = value; + variables[variable]->previous = previous; + variables[variable]->scope = current_scope; + } + + return 0; +} + + +/** + * Get the value currently assigned to a variable + * + * The function cannot fail, `NULL` is however returned + * if the variable is not defined + * + * @param variable The variable index + * @return The variable's value, `NULL` if not defined + */ +mds_kbdc_tree_t* variables_get(size_t variable) +{ + if (variable >= variable_count) return NULL; + if (variables[variable] == NULL) return NULL; + return variables[variable]->value; +} + diff --git a/src/mds-kbdc/variables.h b/src/mds-kbdc/variables.h new file mode 100644 index 0000000..26d3c72 --- /dev/null +++ b/src/mds-kbdc/variables.h @@ -0,0 +1,80 @@ +/** + * mds — A micro-display server + * Copyright © 2014 Mattias Andrée (maandree@member.fsf.org) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef MDS_MDS_KBDC_VARIABLES_H +#define MDS_MDS_KBDC_VARIABLES_H + + +#include "parsed.h" +#include "string.h" + + + +/** + * Destroy the variable storage + */ +void variables_terminate(void); + +/** + * Push the variable-stack, making it + * possible to shadow all variables + * + * @return Zero on success, -1 on error + */ +void variables_stack_push(void); + +/** + * Undo the actions of `variables_stack_push` + * and all additions to the variable storage + * since it was last called (without a + * corresponding call to this function) + */ +void variables_stack_pop(void); + +/** + * Check whether a let will override a variable + * rather the define or shadow it + * + * @param variable The variable index + * @return Whether a let will override the variable + */ +int variables_let_will_override(size_t variable) __attribute__((pure)); + +/** + * Assign a value to a variable, and define or shadow it in the process + * + * @param variable The variable index + * @param value The variable's new value + * @return Zero on success, -1 on error + */ +int variables_let(size_t variable, mds_kbdc_tree_t* restrict value); + +/** + * Get the value currently assigned to a variable + * + * The function cannot fail, `NULL` is however returned + * if the variable is not defined + * + * @param variable The variable index + * @return The variable's value, `NULL` if not defined + */ +mds_kbdc_tree_t* variables_get(size_t variable) __attribute__((pure)); + + + +#endif + |