summaryrefslogtreecommitdiff
path: root/src/lang.c
diff options
context:
space:
mode:
authorStefan Eßer <se@FreeBSD.org>2020-06-27 15:03:19 +0000
committerStefan Eßer <se@FreeBSD.org>2020-06-27 15:03:19 +0000
commit1f958cfad78842ab9a1193471589231e25596cb3 (patch)
tree4bbff8044605fcfff11c9d322bb6f53495e4faa7 /src/lang.c
Diffstat (limited to 'src/lang.c')
-rw-r--r--src/lang.c313
1 files changed, 313 insertions, 0 deletions
diff --git a/src/lang.c b/src/lang.c
new file mode 100644
index 000000000000..6959af80fbfe
--- /dev/null
+++ b/src/lang.c
@@ -0,0 +1,313 @@
+/*
+ * *****************************************************************************
+ *
+ * Copyright (c) 2018-2020 Gavin D. Howard and contributors.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * *****************************************************************************
+ *
+ * Code to manipulate data structures in programs.
+ *
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <lang.h>
+#include <vm.h>
+
+#ifndef NDEBUG
+void bc_id_free(void *id) {
+ BC_SIG_ASSERT_LOCKED;
+ assert(id != NULL);
+ free(((BcId*) id)->name);
+}
+#endif // NDEBUG
+
+void bc_string_free(void *string) {
+ BC_SIG_ASSERT_LOCKED;
+ assert(string != NULL && (*((char**) string)) != NULL);
+ if (BC_IS_BC) free(*((char**) string));
+}
+
+void bc_const_free(void *constant) {
+ BcConst *c = constant;
+ BC_SIG_ASSERT_LOCKED;
+ assert(c->val != NULL);
+ free(c->val);
+ bc_num_free(&c->num);
+}
+
+#if BC_ENABLED
+void bc_func_insert(BcFunc *f, BcProgram *p, char *name,
+ BcType type, size_t line)
+{
+ BcLoc a;
+ size_t i, idx;
+
+ assert(f != NULL);
+
+ idx = bc_program_search(p, name, type == BC_TYPE_VAR);
+
+ for (i = 0; i < f->autos.len; ++i) {
+ BcLoc *id = bc_vec_item(&f->autos, i);
+ if (BC_ERR(idx == id->loc && type == (BcType) id->idx)) {
+ const char *array = type == BC_TYPE_ARRAY ? "[]" : "";
+ bc_vm_error(BC_ERROR_PARSE_DUP_LOCAL, line, name, array);
+ }
+ }
+
+ a.loc = idx;
+ a.idx = type;
+
+ bc_vec_push(&f->autos, &a);
+}
+#endif // BC_ENABLED
+
+void bc_func_init(BcFunc *f, const char *name) {
+
+ BC_SIG_ASSERT_LOCKED;
+
+ assert(f != NULL && name != NULL);
+
+ bc_vec_init(&f->code, sizeof(uchar), NULL);
+
+ // This is necessary for not allocating memory where it isn't used.
+ // dc does not use strings except in the main function. The else part
+ // is necessary to stop uninitiazed data errors in valgrind.
+ if (BC_IS_BC || !strcmp(name, bc_func_main))
+ bc_vec_init(&f->strs, sizeof(char*), bc_string_free);
+#if BC_ENABLE_FUNC_FREE
+ else bc_vec_clear(&f->strs);
+#endif // BC_ENABLE_FUNC_FREE
+
+ bc_vec_init(&f->consts, sizeof(BcConst), bc_const_free);
+#if BC_ENABLED
+ if (BC_IS_BC) {
+ bc_vec_init(&f->autos, sizeof(BcLoc), NULL);
+ bc_vec_init(&f->labels, sizeof(size_t), NULL);
+ f->nparams = 0;
+ f->voidfn = false;
+ }
+#endif // BC_ENABLED
+ f->name = name;
+}
+
+void bc_func_reset(BcFunc *f) {
+ BC_SIG_ASSERT_LOCKED;
+ assert(f != NULL);
+ bc_vec_npop(&f->code, f->code.len);
+ bc_vec_npop(&f->strs, f->strs.len);
+ bc_vec_npop(&f->consts, f->consts.len);
+#if BC_ENABLED
+ if (BC_IS_BC) {
+ bc_vec_npop(&f->autos, f->autos.len);
+ bc_vec_npop(&f->labels, f->labels.len);
+ f->nparams = 0;
+ f->voidfn = false;
+ }
+#endif // BC_ENABLED
+}
+
+void bc_func_free(void *func) {
+#if BC_ENABLE_FUNC_FREE
+
+ BcFunc *f = (BcFunc*) func;
+ BC_SIG_ASSERT_LOCKED;
+ assert(f != NULL);
+ bc_vec_free(&f->code);
+ bc_vec_free(&f->strs);
+ bc_vec_free(&f->consts);
+#if BC_ENABLED
+#ifndef NDEBUG
+ if (BC_IS_BC) {
+ bc_vec_free(&f->autos);
+ bc_vec_free(&f->labels);
+ }
+#endif // NDEBUG
+#endif // BC_ENABLED
+
+#else // BC_ENABLE_FUNC_FREE
+ BC_UNUSED(func);
+#endif // BC_ENABLE_FUNC_FREE
+}
+
+void bc_array_init(BcVec *a, bool nums) {
+ BC_SIG_ASSERT_LOCKED;
+ if (nums) bc_vec_init(a, sizeof(BcNum), bc_num_free);
+ else bc_vec_init(a, sizeof(BcVec), bc_vec_free);
+ bc_array_expand(a, 1);
+}
+
+void bc_array_copy(BcVec *d, const BcVec *s) {
+
+ size_t i;
+
+ BC_SIG_ASSERT_LOCKED;
+
+ assert(d != NULL && s != NULL);
+ assert(d != s && d->size == s->size && d->dtor == s->dtor);
+
+ bc_vec_npop(d, d->len);
+ bc_vec_expand(d, s->cap);
+ d->len = s->len;
+
+ for (i = 0; i < s->len; ++i) {
+ BcNum *dnum = bc_vec_item(d, i), *snum = bc_vec_item(s, i);
+ bc_num_createCopy(dnum, snum);
+ }
+}
+
+void bc_array_expand(BcVec *a, size_t len) {
+
+ assert(a != NULL);
+
+ BC_SIG_ASSERT_LOCKED;
+
+ bc_vec_expand(a, len);
+
+ if (a->size == sizeof(BcNum) && a->dtor == bc_num_free) {
+ BcNum n;
+ while (len > a->len) {
+ bc_num_init(&n, BC_NUM_DEF_SIZE);
+ bc_vec_push(a, &n);
+ }
+ }
+ else {
+ BcVec v;
+ assert(a->size == sizeof(BcVec) && a->dtor == bc_vec_free);
+ while (len > a->len) {
+ bc_array_init(&v, true);
+ bc_vec_push(a, &v);
+ }
+ }
+}
+
+void bc_result_clear(BcResult *r) {
+ r->t = BC_RESULT_TEMP;
+ bc_num_clear(&r->d.n);
+}
+
+#if DC_ENABLED
+void bc_result_copy(BcResult *d, BcResult *src) {
+
+ assert(d != NULL && src != NULL);
+
+ BC_SIG_ASSERT_LOCKED;
+
+ d->t = src->t;
+
+ switch (d->t) {
+
+ case BC_RESULT_TEMP:
+ case BC_RESULT_IBASE:
+ case BC_RESULT_SCALE:
+ case BC_RESULT_OBASE:
+#if BC_ENABLE_EXTRA_MATH
+ case BC_RESULT_SEED:
+#endif // BC_ENABLE_EXTRA_MATH
+ {
+ bc_num_createCopy(&d->d.n, &src->d.n);
+ break;
+ }
+
+ case BC_RESULT_VAR:
+#if BC_ENABLED
+ case BC_RESULT_ARRAY:
+#endif // BC_ENABLED
+ case BC_RESULT_ARRAY_ELEM:
+ {
+ memcpy(&d->d.loc, &src->d.loc, sizeof(BcLoc));
+ break;
+ }
+
+ case BC_RESULT_CONSTANT:
+ case BC_RESULT_STR:
+ {
+ memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
+ break;
+ }
+
+ case BC_RESULT_ONE:
+ {
+ // Do nothing.
+ break;
+ }
+
+#if BC_ENABLED
+ case BC_RESULT_VOID:
+ case BC_RESULT_LAST:
+ {
+#ifndef NDEBUG
+ abort();
+#endif // NDEBUG
+ }
+#endif // BC_ENABLED
+ }
+}
+#endif // DC_ENABLED
+
+void bc_result_free(void *result) {
+
+ BcResult *r = (BcResult*) result;
+
+ BC_SIG_ASSERT_LOCKED;
+
+ assert(r != NULL);
+
+ switch (r->t) {
+
+ case BC_RESULT_TEMP:
+ case BC_RESULT_IBASE:
+ case BC_RESULT_SCALE:
+ case BC_RESULT_OBASE:
+#if BC_ENABLE_EXTRA_MATH
+ case BC_RESULT_SEED:
+#endif // BC_ENABLE_EXTRA_MATH
+ {
+ bc_num_free(&r->d.n);
+ break;
+ }
+
+ case BC_RESULT_VAR:
+#if BC_ENABLED
+ case BC_RESULT_ARRAY:
+#endif // BC_ENABLED
+ case BC_RESULT_ARRAY_ELEM:
+ case BC_RESULT_STR:
+ case BC_RESULT_CONSTANT:
+ case BC_RESULT_ONE:
+#if BC_ENABLED
+ case BC_RESULT_VOID:
+ case BC_RESULT_LAST:
+#endif // BC_ENABLED
+ {
+ // Do nothing.
+ break;
+ }
+ }
+}