From be839900419c7a74c4a46efd279d0ca16b35dc1f Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Thu, 15 May 2008 23:28:07 +0000 Subject: Moved stuff into trunk. --- src/core/convert.c | 185 ++++++++++ src/core/convert.h | 53 +++ src/core/function.c | 661 +++++++++++++++++++++++++++++++++++ src/core/function.h | 50 +++ src/core/garbage.c | 136 ++++++++ src/core/garbage.h | 54 +++ src/core/interpret.c | 946 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/core/interpret.h | 75 ++++ src/core/scanner.c | 391 +++++++++++++++++++++ src/core/scanner.h | 71 ++++ src/core/scope.c | 150 ++++++++ src/core/scope.h | 59 ++++ src/core/symbol.c | 66 ++++ src/core/symbol.h | 64 ++++ src/core/token.c | 380 +++++++++++++++++++++ src/core/token.h | 183 ++++++++++ 16 files changed, 3524 insertions(+) create mode 100644 src/core/convert.c create mode 100644 src/core/convert.h create mode 100644 src/core/function.c create mode 100644 src/core/function.h create mode 100644 src/core/garbage.c create mode 100644 src/core/garbage.h create mode 100644 src/core/interpret.c create mode 100644 src/core/interpret.h create mode 100644 src/core/scanner.c create mode 100644 src/core/scanner.h create mode 100644 src/core/scope.c create mode 100644 src/core/scope.h create mode 100644 src/core/symbol.c create mode 100644 src/core/symbol.h create mode 100644 src/core/token.c create mode 100644 src/core/token.h (limited to 'src/core') diff --git a/src/core/convert.c b/src/core/convert.c new file mode 100644 index 0000000..0d63619 --- /dev/null +++ b/src/core/convert.c @@ -0,0 +1,185 @@ +/*:* + *: File: ./src/core/convert.c + *: A simple interpreter + *: + *: WWW : http://fype.buetow.org + *: E-Mail : fype@dev.buetow.org + *: + *: Copyright (c) 2005 2006 2007 2008, Paul Buetow (http://www.pblabs.net) + *: All rights reserved. + *: + *: Redistribution and use in source and binary forms, with or without modi- + *: fication, 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. + *: * Neither the name of P. B. Labs nor the names of its contributors may + *: be used to endorse or promote products derived from this software + *: without specific prior written permission. + *: + *: THIS SOFTWARE IS PROVIDED BY Paul Buetow 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 Paul Buetow 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. + *:*/ + +#include "convert.h" + +void +convert_to_integer(Token *p_token) { + switch (token_get_tt(p_token)) { + case TT_INTEGER: + break; + case TT_DOUBLE: + token_set_tt(p_token, TT_INTEGER); + token_set_ival(p_token, (int)token_get_dval(p_token)); + break; + case TT_STRING: + token_set_tt(p_token, TT_INTEGER); + token_set_ival(p_token, atoi(token_get_val(p_token))); + break; + default: + ERROR("Ouups(%s)", tt_get_name(token_get_tt(p_token))); + break; + } +} + +int +convert_to_integer_get(Token *p_token) { + switch (token_get_tt(p_token)) { + case TT_INTEGER: + return (token_get_ival(p_token)); + case TT_DOUBLE: + return ((int) token_get_dval(p_token)); + case TT_STRING: + return (atoi(token_get_val(p_token))); + default: + ERROR("Ouups(%s)", tt_get_name(token_get_tt(p_token))); + } + + return (0); /* Never reach this point */ +} + +void +convert_to_double(Token *p_token) { + switch (token_get_tt(p_token)) { + case TT_INTEGER: + token_set_tt(p_token, TT_DOUBLE); + token_set_dval(p_token, token_get_ival(p_token)); + break; + case TT_DOUBLE: + break; + case TT_STRING: + token_set_tt(p_token, TT_DOUBLE); + token_set_dval(p_token, atof(token_get_val(p_token))); + break; + default: + token_print_val(p_token); + ERROR("Datatype conversion error '%s'", token_get_val(p_token)); + break; + } +} + +void +convert_to_string(Token *p_token) { + switch (token_get_tt(p_token)) { + case TT_INTEGER: + { + token_set_tt(p_token, TT_STRING); + char c_tmp[1024]; + sprintf(c_tmp, "%d", token_get_ival(p_token)); + int i_len = strlen(c_tmp); + p_token->c_val = realloc(p_token->c_val, sizeof(char) * (i_len + 1)); + strcpy(p_token->c_val, c_tmp); + p_token->c_val[i_len] = 0; + } + break; + case TT_DOUBLE: + { + token_set_tt(p_token, TT_STRING); + char c_tmp[1024]; + sprintf(c_tmp, "%f", token_get_dval(p_token)); + int i_len = strlen(c_tmp); + p_token->c_val = realloc(p_token->c_val, sizeof(char) * (i_len + 1)); + strcpy(p_token->c_val, c_tmp); + p_token->c_val[i_len] = 0; + } + break; + case TT_STRING: + break; + default: + ERROR("Datatype conversion error"); + break; + } +} + +void +convert_to_tt(Token *p_token, TokenType tt) { + switch (tt) { + case TT_INTEGER: + convert_to_integer(p_token); + break; + case TT_DOUBLE: + convert_to_double(p_token); + break; + case TT_STRING: + convert_to_string(p_token); + break; + default: + ERROR("Ouups!"); + } +} + +TokenType +convert_to_highest(Token *p_token1, Token *p_token2) { + TokenType tt_highest = token_get_tt(p_token1); + + if (tt_highest < token_get_tt(p_token2)) { + tt_highest = token_get_tt(p_token2); + + convert_to_tt(p_token1, tt_highest); + + } else { + convert_to_tt(p_token2, tt_highest); + } + + return (tt_highest); +} + +TokenType +convert_function_arg_types_to_highest(Stack *p_stack_args, int i_args) { + + if (i_args <= 0) + i_args = stack_size(p_stack_args); + + StackIterator *p_iter = stackiterator_new(p_stack_args); + TokenType tt_highest = TT_INTEGER; + + for (int i = 0; i < i_args && stackiterator_has_next(p_iter); ++i) { + Token *p_token = stackiterator_next(p_iter); + if (token_get_tt(p_token) > tt_highest) + tt_highest = token_get_tt(p_token); + } + + stackiterator_delete(p_iter); + p_iter = stackiterator_new(p_stack_args); + + for (int i = 0; i < i_args && stackiterator_has_next(p_iter); ++i) { + Token *p_token = stackiterator_next(p_iter); + convert_to_tt(p_token, tt_highest); + } + + stackiterator_delete(p_iter); + + return (tt_highest); +} + diff --git a/src/core/convert.h b/src/core/convert.h new file mode 100644 index 0000000..c4e0b1d --- /dev/null +++ b/src/core/convert.h @@ -0,0 +1,53 @@ +/*:* + *: File: ./src/core/convert.h + *: A simple interpreter + *: + *: WWW : http://fype.buetow.org + *: E-Mail : fype@dev.buetow.org + *: + *: Copyright (c) 2005 2006 2007 2008, Paul Buetow (http://www.pblabs.net) + *: All rights reserved. + *: + *: Redistribution and use in source and binary forms, with or without modi- + *: fication, 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. + *: * Neither the name of P. B. Labs nor the names of its contributors may + *: be used to endorse or promote products derived from this software + *: without specific prior written permission. + *: + *: THIS SOFTWARE IS PROVIDED BY Paul Buetow 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 Paul Buetow 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. + *:*/ + +#ifndef CONVERT_H +#define CONVERT_H + +#include "../defines.h" + +#include "../data/stack.h" + +#include "token.h" + +int convert_to_integer_get(Token *p_token); +void convert_to_integer(Token *p_token); +void convert_to_double(Token *p_token); +void convert_to_string(Token *p_token); +void convert_to_tt(Token *p_token, TokenType tt); +TokenType convert_to_highest(Token *p_token1, Token *p_token2); +TokenType convert_function_arg_types_to_highest(Stack *p_stack_args, int + i_args); + +#endif diff --git a/src/core/function.c b/src/core/function.c new file mode 100644 index 0000000..fd18ba0 --- /dev/null +++ b/src/core/function.c @@ -0,0 +1,661 @@ +/*:* + *: File: ./src/core/function.c + *: A simple interpreter + *: + *: WWW : http://fype.buetow.org + *: E-Mail : fype@dev.buetow.org + *: + *: Copyright (c) 2005 2006 2007 2008, Paul Buetow (http://www.pblabs.net) + *: All rights reserved. + *: + *: Redistribution and use in source and binary forms, with or without modi- + *: fication, 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. + *: * Neither the name of P. B. Labs nor the names of its contributors may + *: be used to endorse or promote products derived from this software + *: without specific prior written permission. + *: + *: THIS SOFTWARE IS PROVIDED BY Paul Buetow 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 Paul Buetow 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. + *:*/ + +#include +#include +#include + +#include "function.h" + +#include "convert.h" +#include "scope.h" +#include "symbol.h" + +#define _FUNCTION_ERROR(m,t) \ + ERROR(\ + "%s: Function error in %s line %d pos %d near '%s'", m, \ + token_get_filename(t), \ + token_get_line_nr(t), \ + token_get_pos_nr(t), \ + token_get_val(t) \ + ) + +void +_process(Interpret *p_interpret, Token *p_token_store, Token *p_token_op, + Token *p_token_next) { + + TokenType tt_op = token_get_tt(p_token_op); + +#ifdef DEBUG_FUNCTION_PROCESS + printf("PROCESS OPERATOR %s\n", tt_get_name(tt_op)); + + token_print(p_token_next); + printf("\n"); + token_print(p_token_store); + printf("\n"); +#endif /* DEBUG_FUNCTION_PROCESS */ + + + switch (tt_op) { + case TT_ASSIGN: + { + Token *p_token_assign = p_interpret->p_token_temp; + TokenType tt_assign = token_get_tt(p_token_assign); + + if (tt_assign != TT_IDENT) { + _FUNCTION_ERROR("Can only assign to symbols", + p_token_store); + } + + Symbol *p_symbol = scope_get(p_interpret->p_scope, + token_get_val(p_token_assign)); + + if (p_symbol == NULL) { + _FUNCTION_ERROR("No such symbol", + p_token_assign); + } + + symbol_set_val(p_symbol, p_token_store); + symbol_set_sym(p_symbol, SYM_VARIABLE); + + return; + } + + break; + NO_DEFAULT; + } + + p_token_next = token_new_copy(p_token_next); + TokenType tt_highest = convert_to_highest(p_token_store, p_token_next); + +#ifdef DEBUG_FUNCTION_PROCESS + printf("===> %s %s %s\n", + tt_get_name(tt_highest), + tt_get_name(tt_op), + tt_get_name(tt_highest)); +#endif /* DEBUG_FUNCTION_PROCESS */ + + switch (tt_op) { + case TT_ADD: + switch (tt_highest) { + case TT_INTEGER: + token_set_ival(p_token_store, + token_get_ival(p_token_next) + + token_get_ival(p_token_store)); + break; + case TT_DOUBLE: + token_set_dval(p_token_store, + token_get_dval(p_token_next) + + token_get_dval(p_token_store)); + case TT_STRING: + token_set_ival(p_token_store, + atoi(token_get_val(p_token_next)) + + atoi(token_get_val(p_token_store))); + token_set_tt(p_token_store, TT_INTEGER); + break; + NO_DEFAULT; + } + break; + case TT_SUB: + switch (tt_highest) { + case TT_INTEGER: + token_set_ival(p_token_store, + token_get_ival(p_token_next) - + token_get_ival(p_token_store)); + break; + case TT_DOUBLE: + token_set_dval(p_token_store, + token_get_dval(p_token_next) - + token_get_dval(p_token_store)); + break; + case TT_STRING: + token_set_ival(p_token_store, + atoi(token_get_val(p_token_next)) - + atoi(token_get_val(p_token_store))); + token_set_tt(p_token_store, TT_INTEGER); + break; + NO_DEFAULT; + } + break; + case TT_MULT: + switch (tt_highest) { + case TT_INTEGER: + token_set_ival(p_token_store, + token_get_ival(p_token_next) * + token_get_ival(p_token_store)); + break; + case TT_DOUBLE: + token_set_dval(p_token_store, + token_get_dval(p_token_next) * + token_get_dval(p_token_store)); + break; + case TT_STRING: + token_set_ival(p_token_store, + atoi(token_get_val(p_token_next)) * + atoi(token_get_val(p_token_store))); + token_set_tt(p_token_store, TT_INTEGER); + break; + NO_DEFAULT; + } + break; + case TT_DIV: + switch (tt_highest) { + case TT_INTEGER: + token_set_ival(p_token_store, + (int) token_get_ival(p_token_next) / + token_get_ival(p_token_store)); + break; + case TT_DOUBLE: + token_set_dval(p_token_store, + token_get_dval(p_token_next) / + token_get_dval(p_token_store)); + break; + case TT_STRING: + token_set_dval(p_token_store, + atof(token_get_val(p_token_next)) / + atof(token_get_val(p_token_store))); + token_set_tt(p_token_store, TT_DOUBLE); + break; + NO_DEFAULT; + } + break; + case TT_EQ: + switch (tt_highest) { + case TT_INTEGER: + token_set_ival(p_token_store, + (int) token_get_ival(p_token_next) == + token_get_ival(p_token_store)); + break; + case TT_DOUBLE: + token_set_ival(p_token_store, + token_get_dval(p_token_next) == + token_get_dval(p_token_store)); + token_set_tt(p_token_store, TT_INTEGER); + break; + case TT_STRING: + token_set_ival(p_token_store, + strcmp(token_get_val(p_token_next), + token_get_val(p_token_store)) == 0); + token_set_tt(p_token_store, TT_INTEGER); + break; + NO_DEFAULT; + } + break; + case TT_NEQ: + switch (tt_highest) { + case TT_INTEGER: + token_set_ival(p_token_store, + (int) token_get_ival(p_token_next) != + token_get_ival(p_token_store)); + break; + case TT_DOUBLE: + token_set_ival(p_token_store, + token_get_dval(p_token_next) != + token_get_dval(p_token_store)); + token_set_tt(p_token_store, TT_INTEGER); + break; + case TT_STRING: + token_set_ival(p_token_store, + strcmp(token_get_val(p_token_next), + token_get_val(p_token_store)) != 0); + token_set_tt(p_token_store, TT_INTEGER); + break; + NO_DEFAULT; + } + break; + case TT_LT: + switch (tt_highest) { + case TT_INTEGER: + token_set_ival(p_token_store, + (int) token_get_ival(p_token_next) < + token_get_ival(p_token_store)); + break; + case TT_DOUBLE: + token_set_ival(p_token_store, + token_get_dval(p_token_next) < + token_get_dval(p_token_store)); + token_set_tt(p_token_store, TT_INTEGER); + break; + case TT_STRING: + token_set_ival(p_token_store, + strcmp(token_get_val(p_token_next), + token_get_val(p_token_store)) < 0); + token_set_tt(p_token_store, TT_INTEGER); + break; + NO_DEFAULT; + } + break; + case TT_GT: + switch (tt_highest) { + case TT_INTEGER: + token_set_ival(p_token_store, + (int) token_get_ival(p_token_next) > + token_get_ival(p_token_store)); + break; + case TT_DOUBLE: + token_set_ival(p_token_store, + token_get_dval(p_token_next) > + token_get_dval(p_token_store)); + token_set_tt(p_token_store, TT_INTEGER); + break; + case TT_STRING: + token_set_ival(p_token_store, + strcmp(token_get_val(p_token_next), + token_get_val(p_token_store)) > 0); + token_set_tt(p_token_store, TT_INTEGER); + break; + NO_DEFAULT; + } + break; + case TT_LE: + switch (tt_highest) { + case TT_INTEGER: + token_set_ival(p_token_store, + (int) token_get_ival(p_token_next) <= + token_get_ival(p_token_store)); + break; + case TT_DOUBLE: + token_set_ival(p_token_store, + token_get_dval(p_token_next) <= + token_get_dval(p_token_store)); + token_set_tt(p_token_store, TT_INTEGER); + break; + case TT_STRING: + token_set_ival(p_token_store, + strcmp(token_get_val(p_token_next), + token_get_val(p_token_store)) <= 0); + token_set_tt(p_token_store, TT_INTEGER); + break; + NO_DEFAULT; + } + break; + case TT_GE: + switch (tt_highest) { + case TT_INTEGER: + token_set_ival(p_token_store, + (int) token_get_ival(p_token_next) >= + token_get_ival(p_token_store)); + break; + case TT_DOUBLE: + token_set_ival(p_token_store, + token_get_dval(p_token_next) >= + token_get_dval(p_token_store)); + token_set_tt(p_token_store, TT_INTEGER); + break; + case TT_STRING: + token_set_ival(p_token_store, + strcmp(token_get_val(p_token_next), + token_get_val(p_token_store)) >= 0); + token_set_tt(p_token_store, TT_INTEGER); + break; + NO_DEFAULT; + } + break; + default: + _FUNCTION_ERROR("No such function/operator", p_token_op); + } + +#ifdef DEBUG_FUNCTION_PROCESS + token_print(p_token_store); + printf("\n\n"); +#endif /* DEBUG_FUNCTION_PROCESS */ + + token_delete(p_token_next); +} + +void +function_process(Interpret *p_interpret, Token *p_token_op, + Stack *p_stack_args, int i_args) { + + Token *p_token_store = token_new_copy(stack_pop(p_stack_args)); + + for (int i = 0; i < i_args -1 && !stack_empty(p_stack_args); ++i) { + Token *p_token_next = stack_pop(p_stack_args); + + _process(p_interpret, p_token_store, p_token_op, p_token_next); + } + + stack_push(p_stack_args, p_token_store); +} + +_Bool +function_is_buildin(Token *p_token_ident) { + if (strcmp("assert", token_get_val(p_token_ident)) == 0) + return (true); + + if (strcmp("decr", token_get_val(p_token_ident)) == 0) + return (true); + + if (strcmp("double", token_get_val(p_token_ident)) == 0) + return (true); + + if (strcmp("end", token_get_val(p_token_ident)) == 0) + return (true); + + if (strcmp("exit", token_get_val(p_token_ident)) == 0) + return (true); + + if (strcmp("fork", token_get_val(p_token_ident)) == 0) + return (true); + + if (strcmp("gc", token_get_val(p_token_ident)) == 0) + return (true); + + if (strcmp("incr", token_get_val(p_token_ident)) == 0) + return (true); + + if (strcmp("integer", token_get_val(p_token_ident)) == 0) + return (true); + + if (strcmp("ln", token_get_val(p_token_ident)) == 0) + return (true); + + if (strcmp("neg", token_get_val(p_token_ident)) == 0) + return (true); + + if (strcmp("no", token_get_val(p_token_ident)) == 0) + return (true); + + if (strcmp("put", token_get_val(p_token_ident)) == 0) + return (true); + + if (strcmp("say", token_get_val(p_token_ident)) == 0) + return (true); + + if (strcmp("string", token_get_val(p_token_ident)) == 0) + return (true); + + if (strcmp("yes", token_get_val(p_token_ident)) == 0) + return (true); + + return (false); +} + +void +function_process_buildin(Interpret *p_interpret, Token *p_token_ident, + Stack *p_stack_args) { + + if (strcmp("assert", token_get_val(p_token_ident)) == 0) { + if (0 == stack_size(p_stack_args)) + _FUNCTION_ERROR("No argument given", p_token_ident); + + Token *p_token = stack_top(p_stack_args); + + switch (token_get_tt(p_token)) { + case TT_INTEGER: + if (token_get_ival(p_token) == 0) + _FUNCTION_ERROR("Assert failed", p_token); + break; + case TT_DOUBLE: + if (token_get_dval(p_token) == 0) + _FUNCTION_ERROR("Assert failed", p_token); + break; + case TT_STRING: + if (atoi(token_get_val(p_token)) == 0) + _FUNCTION_ERROR("Assert failed", p_token); + break; + NO_DEFAULT; + } + + } else if (strcmp("decr", token_get_val(p_token_ident)) == 0) { + if (0 == stack_size(p_stack_args)) + _FUNCTION_ERROR("No argument given", p_token_ident); + + Token *p_token = stack_top(p_stack_args); + switch (token_get_tt(p_token)) { + case TT_INTEGER: + token_set_ival(p_token, token_get_ival(p_token) - 1); + break; + case TT_DOUBLE: + token_set_dval(p_token, token_get_dval(p_token) - 1); + break; + case TT_STRING: + convert_to_integer(p_token); + token_set_ival(p_token, token_get_ival(p_token) - 1); + break; + NO_DEFAULT; + } + + } else if (strcmp("double", token_get_val(p_token_ident)) == 0) { + if (0 == stack_size(p_stack_args)) + _FUNCTION_ERROR("No argument given", p_token_ident); + + Token *p_token = token_new_copy(stack_pop(p_stack_args)); + convert_to_double(p_token); + stack_push(p_stack_args, p_token); + + } else if (strcmp("end", token_get_val(p_token_ident)) == 0) { + exit(0); + + } else if (strcmp("fork", token_get_val(p_token_ident)) == 0) { + Token *p_token = token_new_integer((int) fork()); + stack_push(p_stack_args, p_token); + + } else if (strcmp("gc", token_get_val(p_token_ident)) == 0) { + int i_count = garbage_collect(); + printf("ICOUNT %d\n", i_count); + Token *p_token = token_new_integer(i_count); + stack_push(p_stack_args, p_token); + + } else if (strcmp("exit", token_get_val(p_token_ident)) == 0) { + if (0 == stack_size(p_stack_args)) + _FUNCTION_ERROR("No argument given", p_token_ident); + + Token *p_token = stack_top(p_stack_args); + p_token = token_new_copy(p_token); + convert_to_integer(p_token); + exit(token_get_ival(p_token)); + + } else if (strcmp("incr", token_get_val(p_token_ident)) == 0) { + if (0 == stack_size(p_stack_args)) + _FUNCTION_ERROR("No argument given", p_token_ident); + + Token *p_token = stack_top(p_stack_args); + switch (token_get_tt(p_token)) { + case TT_INTEGER: + token_set_ival(p_token, token_get_ival(p_token) + 1); + break; + case TT_DOUBLE: + token_set_dval(p_token, token_get_dval(p_token) + 1); + break; + case TT_STRING: + convert_to_integer(p_token); + token_set_ival(p_token, token_get_ival(p_token) + 1); + break; + NO_DEFAULT; + } + + } else if (strcmp("integer", token_get_val(p_token_ident)) == 0) { + if (0 == stack_size(p_stack_args)) + _FUNCTION_ERROR("No argument given", p_token_ident); + + Token *p_token = token_new_copy(stack_pop(p_stack_args)); + convert_to_integer(p_token); + stack_push(p_stack_args, p_token); + + } else if (strcmp("ln", token_get_val(p_token_ident)) == 0) { + printf("\n"); + + } else if (strcmp("neg", token_get_val(p_token_ident)) == 0) { + if (0 == stack_size(p_stack_args)) + _FUNCTION_ERROR("No argument given", p_token_ident); + + Token *p_token = token_new_copy(stack_pop(p_stack_args)); + stack_push(p_stack_args, p_token); + + switch (token_get_tt(p_token)) { + case TT_INTEGER: + token_set_ival(p_token, -token_get_ival(p_token)); + break; + case TT_DOUBLE: + token_set_dval(p_token, -token_get_dval(p_token)); + break; + case TT_STRING: + token_set_ival(p_token, -atoi(token_get_val(p_token))); + token_set_tt(p_token, TT_INTEGER); + break; + NO_DEFAULT; + } + + } else if (strcmp("no", token_get_val(p_token_ident)) == 0) { + Token *p_token = NULL; + + if (0 == stack_size(p_stack_args)) { + p_token = token_new_integer(0); + + } else { + p_token = token_new_copy(stack_pop(p_stack_args)); + + switch (token_get_tt(p_token)) { + case TT_INTEGER: + token_set_ival(p_token, !token_get_ival(p_token)); + break; + case TT_DOUBLE: + token_set_dval(p_token, !token_get_dval(p_token)); + break; + case TT_STRING: + token_set_ival(p_token, !atoi(token_get_val(p_token))); + token_set_tt(p_token, TT_INTEGER); + break; + NO_DEFAULT; + } + } + + stack_push(p_stack_args, p_token); + + } else if (strcmp("put", token_get_val(p_token_ident)) == 0) { + StackIterator *p_iter = stackiterator_new(p_stack_args); + while (stackiterator_has_next(p_iter)) { + Token *p_token = stackiterator_next(p_iter); + switch (token_get_tt(p_token)) { + case TT_INTEGER: + printf("%d", token_get_ival(p_token)); + break; + case TT_DOUBLE: + printf("%f", token_get_dval(p_token)); + break; + case TT_STRING: + printf("%s", token_get_val(p_token)); + break; + NO_DEFAULT; + } + } + stackiterator_delete(p_iter); + + } else if (strcmp("say", token_get_val(p_token_ident)) == 0) { + StackIterator *p_iter = stackiterator_new(p_stack_args); + while (stackiterator_has_next(p_iter)) { + Token *p_token = stackiterator_next(p_iter); + switch (token_get_tt(p_token)) { + case TT_INTEGER: + printf("%d", token_get_ival(p_token)); + break; + case TT_DOUBLE: + printf("%f", token_get_dval(p_token)); + break; + case TT_STRING: + printf("%s", token_get_val(p_token)); + break; + NO_DEFAULT; + } + } + stackiterator_delete(p_iter); + printf("\n"); + + } else if (strcmp("string", token_get_val(p_token_ident)) == 0) { + if (0 == stack_size(p_stack_args)) + _FUNCTION_ERROR("No argument given", p_token_ident); + + Token *p_token = token_new_copy(stack_pop(p_stack_args)); + convert_to_string(p_token); + stack_push(p_stack_args, p_token); + + } else if (strcmp("yes", token_get_val(p_token_ident)) == 0) { + Token *p_token = NULL; + + if (0 == stack_size(p_stack_args)) { + p_token = token_new_integer(1); + + } else { + p_token = token_new_copy(stack_pop(p_stack_args)); + token_set_ival(p_token, 1); + token_set_tt(p_token, TT_INTEGER); + + } + + stack_push(p_stack_args, p_token); + } +} + +_Bool +function_is_self_defined(Interpret *p_interpret) { + Symbol *p_symbol = scope_get(p_interpret->p_scope, + token_get_val(p_interpret->p_token)); + + if (p_symbol == NULL) + return (false); + + switch (symbol_get_sym(p_symbol)) { + case SYM_PROCEDURE: + case SYM_FUNCTION: + return (true); + NO_DEFAULT; + } + + return (false); +} + +void +function_process_self_defined(Interpret *p_interpret, Token *p_token_ident) { + Symbol *p_symbol = scope_get(p_interpret->p_scope, + token_get_val(p_token_ident)); + + switch (symbol_get_sym(p_symbol)) { + case SYM_PROCEDURE: + { + List *p_list_token = symbol_get_val(p_symbol); + interpret_subprocess(p_interpret, p_list_token); + } + break; + case SYM_FUNCTION: + { + List *p_list_token = symbol_get_val(p_symbol); + scope_up(p_interpret->p_scope); + interpret_subprocess(p_interpret, p_list_token); + scope_down(p_interpret->p_scope); + } + NO_DEFAULT; + } +} + diff --git a/src/core/function.h b/src/core/function.h new file mode 100644 index 0000000..9f12bb4 --- /dev/null +++ b/src/core/function.h @@ -0,0 +1,50 @@ +/*:* + *: File: ./src/core/function.h + *: A simple interpreter + *: + *: WWW : http://fype.buetow.org + *: E-Mail : fype@dev.buetow.org + *: + *: Copyright (c) 2005 2006 2007 2008, Paul Buetow (http://www.pblabs.net) + *: All rights reserved. + *: + *: Redistribution and use in source and binary forms, with or without modi- + *: fication, 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. + *: * Neither the name of P. B. Labs nor the names of its contributors may + *: be used to endorse or promote products derived from this software + *: without specific prior written permission. + *: + *: THIS SOFTWARE IS PROVIDED BY Paul Buetow 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 Paul Buetow 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. + *:*/ + +#ifndef FUNCTION_H +#define FUNCTION_H + +#include "token.h" + +#include "interpret.h" +#include "../data/stack.h" + +void function_process(Interpret *p_interp, Token *p_token_op, Stack + *p_stack_args, int i_args); +_Bool function_is_buildin(Token *p_token_ident); +void function_process_buildin(Interpret *p_interpret, Token *p_token_ident, Stack *p_stack_args); +_Bool function_is_self_defined(Interpret *p_interpret); +void function_process_self_defined(Interpret *p_interpret, Token *p_token_ident); + +#endif /* FUNCTION_H */ diff --git a/src/core/garbage.c b/src/core/garbage.c new file mode 100644 index 0000000..b4dad22 --- /dev/null +++ b/src/core/garbage.c @@ -0,0 +1,136 @@ +/*:* + *: File: ./src/core/garbage.c + *: A simple interpreter + *: + *: WWW : http://fype.buetow.org + *: E-Mail : fype@dev.buetow.org + *: + *: Copyright (c) 2005 2006 2007 2008, Paul Buetow (http://www.pblabs.net) + *: All rights reserved. + *: + *: Redistribution and use in source and binary forms, with or without modi- + *: fication, 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. + *: * Neither the name of P. B. Labs nor the names of its contributors may + *: be used to endorse or promote products derived from this software + *: without specific prior written permission. + *: + *: THIS SOFTWARE IS PROVIDED BY Paul Buetow 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 Paul Buetow 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. + *:*/ + +#include "garbage.h" + +#define _GARBAGE_ERROR(m) \ + ERROR("%s: Garbage error", m); + +List *LIST_GARBAGE = NULL; + +typedef struct { + void (*p_func)(void*); + int *p_ref_count; + void *p_2free; + GarbageType type; +} _Garbage; + +void +garbage_init() { + LIST_GARBAGE = list_new(); +} + +void +_garbage_print(_Garbage *p_garbage) { + switch (p_garbage->type) { + case GC_TOKEN: + { + Token *p_token = p_garbage->p_2free; + token_print(p_token); + printf("\n"); + } + break; + } +} + +void +garbage_destroy() { + garbage_collect(); + + if (!list_empty(LIST_GARBAGE)) { + EPRINTF("The garbage collector still has %d registered items which don't have" + " a zero ref count!\n", list_size(LIST_GARBAGE)); + + ListIterator *p_iter = listiterator_new(LIST_GARBAGE); + while (listiterator_has_next(p_iter)) { + _Garbage *p_garbage = listiterator_next(p_iter); + _garbage_print(p_garbage); + } + listiterator_delete(p_iter); + + _GARBAGE_ERROR("Garbage left"); + } + + list_delete(LIST_GARBAGE); +} + +int +garbage_collect() { + ListIterator *p_iter = listiterator_new(LIST_GARBAGE); + List *p_list_garbage_new = list_new(); + int i_count = 0; + + while (listiterator_has_next(p_iter)) { + _Garbage *p_garbage = listiterator_next(p_iter); + + if (p_garbage->p_ref_count == NULL || *p_garbage->p_ref_count <= 0) { + // _garbage_print(p_garbage); + (*p_garbage->p_func) (p_garbage->p_2free); + free(p_garbage); + ++i_count; + + } else { + list_add_back(p_list_garbage_new, p_garbage); + } + } + + listiterator_delete(p_iter); + + list_delete(LIST_GARBAGE); + LIST_GARBAGE = p_list_garbage_new; + + return (i_count); +} + +void +garbage_add(void *p, GarbageType type) { + garbage_add2(p, free, NULL, type); +} + +void +garbage_add2(void *p, void (*p_func)(void*), int *p_ref_count, GarbageType type) { + _Garbage *p_garbage = malloc(sizeof(_Garbage)); + + p_garbage->p_2free = p; + p_garbage->p_func = p_func; + p_garbage->p_ref_count = p_ref_count; + p_garbage->type = type; + + list_add_back(LIST_GARBAGE, p_garbage); +} + +void +garbage_add_token(Token *p_token) { + garbage_add2(p_token, token_delete_cb, &p_token->i_ref_count, GC_TOKEN); +} diff --git a/src/core/garbage.h b/src/core/garbage.h new file mode 100644 index 0000000..6a8007d --- /dev/null +++ b/src/core/garbage.h @@ -0,0 +1,54 @@ +/*:* + *: File: ./src/core/garbage.h + *: A simple interpreter + *: + *: WWW : http://fype.buetow.org + *: E-Mail : fype@dev.buetow.org + *: + *: Copyright (c) 2005 2006 2007 2008, Paul Buetow (http://www.pblabs.net) + *: All rights reserved. + *: + *: Redistribution and use in source and binary forms, with or without modi- + *: fication, 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. + *: * Neither the name of P. B. Labs nor the names of its contributors may + *: be used to endorse or promote products derived from this software + *: without specific prior written permission. + *: + *: THIS SOFTWARE IS PROVIDED BY Paul Buetow 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 Paul Buetow 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. + *:*/ + +#ifndef GARBAGE_H +#define GARBAGE_H + +#include "../defines.h" +#include "../data/list.h" +#include "token.h" + +typedef enum { + GC_TOKEN, +} GarbageType; + +void garbage_init(); +void garbage_destroy(); +int garbage_collect(); +void garbage_add(void *p, GarbageType type); +void garbage_add2(void *p, void (*p_func)(void*), int *p_ref_count, + GarbageType type); +void garbage_add_token(Token *p_token); + +#endif diff --git a/src/core/interpret.c b/src/core/interpret.c new file mode 100644 index 0000000..97e19c2 --- /dev/null +++ b/src/core/interpret.c @@ -0,0 +1,946 @@ +/*:* + *: File: ./src/core/interpret.c + *: A simple interpreter + *: + *: WWW : http://fype.buetow.org + *: E-Mail : fype@dev.buetow.org + *: + *: Copyright (c) 2005 2006 2007 2008, Paul Buetow (http://www.pblabs.net) + *: All rights reserved. + *: + *: Redistribution and use in source and binary forms, with or without modi- + *: fication, 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. + *: * Neither the name of P. B. Labs nor the names of its contributors may + *: be used to endorse or promote products derived from this software + *: without specific prior written permission. + *: + *: THIS SOFTWARE IS PROVIDED BY Paul Buetow 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 Paul Buetow 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. + *:*/ + +#include "interpret.h" + +#include "../defines.h" +#include "convert.h" +#include "function.h" +#include "symbol.h" + +#define _INTERPRET_ERROR(m,t) \ + ERROR(\ + "%s: Interpret error in %s line %d pos %d near '%s'", m, \ + token_get_filename(t), \ + token_get_line_nr(t), \ + token_get_pos_nr(t), \ + token_get_val(t) \ + ) + +#define _CHECK if (p_interpret->p_token == NULL) return (0); +#define _HAS_NEXT listiterator_has_next(p_interpret->p_iter) +#define _NEXT if (!_next(p_interpret)) { return (2); } +#define _NEXT_TT _next_tt(p_interpret) +#define _SKIP _next(p_interpret); + +void _print_lookahead(Interpret *p_interpret); +int _next(Interpret *p_interpret); +int _program(Interpret *p_interpret); +int _var_decl(Interpret *p_interpret); +int _var_assign(Interpret *p_interpret); +int _var_list(Interpret *p_interpret); +int _expression_get(Interpret *p_interpret, List *p_list_block); +int _block_get(Interpret *p_interpret, List *p_list_block); +int _block_skip(Interpret *p_interpret); +int _proc_decl(Interpret *p_interpret); +int _func_decl(Interpret *p_interpret); +int _statement(Interpret *p_interpret); +int _block(Interpret *p_interpret); +int _expression(Interpret *p_interpret); +int _expression_(Interpret *p_interpret); +int _control(Interpret *p_interpret); +int _compare(Interpret *p_interpret); +int _sum(Interpret *p_interpret); +int _product(Interpret *p_interpret); +int _product2(Interpret *p_interpret); +int _term(Interpret *p_interpret); + +Interpret* +interpret_new(List *p_list_token, Hash *p_hash_syms) { + Interpret *p_interpret = malloc(sizeof(Interpret)); + + if (p_hash_syms != NULL) { + p_interpret->p_scope = scope_new(p_hash_syms); + p_interpret->b_scope_delete = true; + + } else { + p_interpret->p_scope = NULL; + p_interpret->b_scope_delete = false; + } + + p_interpret->p_list_token = p_list_token; + p_interpret->p_stack = stack_new(); + p_interpret->tt = TT_NONE; + p_interpret->p_token = NULL; + p_interpret->tt_prev = TT_NONE; + p_interpret->p_token_prev = NULL; + p_interpret->p_token_temp = NULL; + p_interpret->ct = CONTROL_NONE; + + return (p_interpret); +} + +void +interpret_delete(Interpret *p_interpret) { + if (!p_interpret) + return; + + if (p_interpret->b_scope_delete) + scope_delete(p_interpret->p_scope); + + stack_delete(p_interpret->p_stack); + free(p_interpret); +} + +void +_print_lookahead(Interpret *p_interpret) { + ListIterator *p_iter = p_interpret->p_iter; + ListIteratorState *p_state = listiterator_get_state(p_iter); + + printf("LOOLAHEAD:\n"); + + token_print(p_interpret->p_token); + printf("\n"); + + while (listiterator_has_next(p_iter)) { + Token *p_token = listiterator_next(p_iter); + token_print(p_token); + printf("\n"); + } + + listiterator_set_state(p_iter, p_state); + listiteratorstate_delete(p_state); +} + +int +_next(Interpret *p_interpret) { + if (listiterator_has_next(p_interpret->p_iter)) { + p_interpret->p_token_prev = p_interpret->p_token; + p_interpret->tt_prev = p_interpret->tt; + + p_interpret->p_token = listiterator_next(p_interpret->p_iter); + p_interpret->tt = token_get_tt(p_interpret->p_token); + return (1); + } + + p_interpret->p_token = NULL; + p_interpret->tt = TT_NONE; + + return (0); +} + +TokenType +_next_tt(Interpret *p_interpret) { + if (listiterator_has_next(p_interpret->p_iter)) { + Token *p_token = listiterator_current(p_interpret->p_iter); + return (token_get_tt(p_token)); + } + + return (TT_NONE); +} + +int +_program(Interpret *p_interpret) { + _CHECK TRACK + + while (_statement(p_interpret) == 1) + garbage_collect(); + + return (1); +} + +int +_var_decl(Interpret *p_interpret) { + _CHECK TRACK + + if (p_interpret->tt == TT_MY) { + if (_NEXT_TT != TT_IDENT) + _INTERPRET_ERROR("'my' expects identifier", p_interpret->p_token); + + _NEXT + + Token *p_token_ident = p_interpret->p_token; + + _var_assign(p_interpret); + _var_list(p_interpret); + + if (p_interpret->tt == TT_SEMICOLON) { + _NEXT + return (1); + + } else if (p_interpret->p_token != NULL) { + _INTERPRET_ERROR("Expected ';'", p_interpret->p_token); + + } else { + _INTERPRET_ERROR("Expected ';' after", p_token_ident); + } + } + + return (0); +} + +int +_var_assign(Interpret *p_interpret) { + _CHECK TRACK + + if (p_interpret->tt == TT_IDENT) { + Token *p_token = p_interpret->p_token; + _NEXT + + char *c_name = token_get_val(p_token); + if (scope_exists(p_interpret->p_scope, c_name)) { + _INTERPRET_ERROR("Symbol already defined", p_token); + } + + if (p_interpret->tt == TT_ASSIGN) { + _NEXT + + Stack *p_stack = p_interpret->p_stack; + p_interpret->p_stack = stack_new(); + + if (_expression_(p_interpret)) { + function_process_buildin(p_interpret, p_token, p_interpret->p_stack); + + stack_merge(p_stack, p_interpret->p_stack); + stack_delete(p_interpret->p_stack); + p_interpret->p_stack = p_stack; + + p_token = stack_top(p_interpret->p_stack); + Symbol *p_symbol = symbol_new(SYM_VARIABLE, p_token); + scope_newset(p_interpret->p_scope, c_name, p_symbol); + + } else { + return (0); + } + + } else { + Token *p_token = token_new_integer(0); + Symbol *p_symbol = symbol_new(SYM_VARIABLE, p_token); + scope_newset(p_interpret->p_scope, c_name, p_symbol); + } + } + + return (1); +} + +int +_var_list(Interpret *p_interpret) { + _CHECK TRACK + + if (p_interpret->tt == TT_COMMA) { + _NEXT + _var_assign(p_interpret); + _var_list(p_interpret); + } + + return (1); +} + +int +_block_get(Interpret *p_interpret, List *p_list_block) { + if (p_interpret->tt != TT_PARANT_CL) + _INTERPRET_ERROR("Expected '{'", p_interpret->p_token); + _NEXT + + int i_num_parant = 0; + + for (;;) { + if (p_interpret->tt == TT_PARANT_CL) { + ++i_num_parant; + + } else if (p_interpret->tt == TT_PARANT_CR) { + if (--i_num_parant == -1) { + _NEXT + break; /* for */ + } + } + + list_add_back(p_list_block, p_interpret->p_token); + + _NEXT + } + +#ifdef DEBUG_BLOCK_GET + printf("====> BLOCK\n"); + list_iterate(p_list_block, token_print_cb); + printf("<==== BLOCK\n"); +#endif /* DEBUG_BLOCK_GET */ + + return (1); +} + +int +_expression_get(Interpret *p_interpret, List *p_list_expression) { + for (;;) { + if (p_interpret->tt == TT_PARANT_CL) { + break; /* for */ + } + + list_add_back(p_list_expression, p_interpret->p_token); + + _NEXT + } + +#ifdef DEBUG_EXPRESSION_GET + printf("====> EXPRESSION\n"); + list_iterate(p_list_expression, token_print_cb); + printf("<==== EXPRESSION\n"); +#endif /* DEBUG_EXPRESSION_GET */ + + return (1); +} + +int +_block_skip(Interpret *p_interpret) { + if (p_interpret->tt != TT_PARANT_CL) + _INTERPRET_ERROR("Expected '{'", p_interpret->p_token); + _NEXT + + int i_num_parant = 0; + + for (;;) { + if (p_interpret->tt == TT_PARANT_CL) { + ++i_num_parant; + + } else if (p_interpret->tt == TT_PARANT_CR) { + if (--i_num_parant == -1) { + _NEXT + break; /* for */ + } + } + + _NEXT + } + + return (1); +} + +int +_proc_decl(Interpret *p_interpret) { + _CHECK TRACK + + if (p_interpret->tt == TT_PROC) { + _NEXT + + if (p_interpret->tt != TT_IDENT) + _INTERPRET_ERROR("Expected identifier", p_interpret->p_token); + + Token *p_token_ident = p_interpret->p_token; + _NEXT + + if (scope_exists(p_interpret->p_scope, token_get_val(p_token_ident))) { + _INTERPRET_ERROR("Symbol already defined", p_token_ident); + } + + List *p_list_proc = list_new(); + + if (_block_get(p_interpret, p_list_proc)) { + + Symbol *p_symbol = symbol_new(SYM_PROCEDURE, p_list_proc); + scope_newset(p_interpret->p_scope, token_get_val(p_token_ident), + p_symbol); + + return (1); + } + + list_delete(p_list_proc); + } + + return (0); +} + +int +_func_decl(Interpret *p_interpret) { + _CHECK TRACK + + if (p_interpret->tt == TT_FUNC) { + _NEXT + + if (p_interpret->tt != TT_IDENT) + _INTERPRET_ERROR("Expected identifier", p_interpret->p_token); + + Token *p_token_ident = p_interpret->p_token; + _NEXT + + if (scope_exists(p_interpret->p_scope, token_get_val(p_token_ident))) { + _INTERPRET_ERROR("Symbol already defined", p_token_ident); + } + + List *p_list_proc = list_new(); + + if (_block_get(p_interpret, p_list_proc)) { + + Symbol *p_symbol = symbol_new(SYM_FUNCTION, p_list_proc); + scope_newset(p_interpret->p_scope, token_get_val(p_token_ident), + p_symbol); + + return (1); + } + + list_delete(p_list_proc); + } + + return (0); +} + +int +_statement(Interpret *p_interpret) { + _CHECK TRACK + + for (int i = 0; i < 2; ++i) { + if (_proc_decl(p_interpret)) return (1); + if (_func_decl(p_interpret)) return (1); + if (_var_decl(p_interpret)) return (1); + if (_control(p_interpret)) return (1); + if (_expression(p_interpret)) return (1); + if (_block(p_interpret)) return (1); + } + + return (0); +} + +int +_block(Interpret *p_interpret) { + if (p_interpret->tt == TT_PARANT_CL) { + List *p_list_block = list_new(); + + if (_block_get(p_interpret, p_list_block)) { + scope_up(p_interpret->p_scope); + interpret_subprocess(p_interpret, p_list_block); + scope_down(p_interpret->p_scope); + list_delete(p_list_block); + return (1); + } + + list_delete(p_list_block); + } + + return (0); +} + +int +_expression(Interpret *p_interpret) { + _CHECK TRACK + + if (_expression_(p_interpret)) { + if (p_interpret->tt == TT_SEMICOLON) { + _NEXT + + } else { + _INTERPRET_ERROR("Expected ';'", p_interpret->p_token); + } + + stack_clear(p_interpret->p_stack); + return (1); + } + + return (0); +} + +int +_expression_(Interpret *p_interpret) { + return (_compare(p_interpret)); +} + +int +_control(Interpret *p_interpret) { + _CHECK TRACK + + Token *p_token = p_interpret->p_token; + + switch (p_interpret->tt) { + case TT_IF: + case TT_IFNOT: + { + TokenType tt = p_interpret->tt; + _NEXT + if (_expression_(p_interpret)) { + Token *p_token_top = stack_pop(p_interpret->p_stack); + List *p_list_block = list_new(); + _block_get(p_interpret, p_list_block); + int ret = 0; + + switch (tt) { + case TT_IF: + if (convert_to_integer_get(p_token_top)) { + scope_up(p_interpret->p_scope); + ret = interpret_subprocess(p_interpret, p_list_block); + scope_down(p_interpret->p_scope); + } + break; + case TT_IFNOT: + if (!convert_to_integer_get(p_token_top)) { + scope_up(p_interpret->p_scope); + ret = interpret_subprocess(p_interpret, p_list_block); + scope_down(p_interpret->p_scope); + } + break; + NO_DEFAULT; + } + + list_delete(p_list_block); + return (1); + + } else { + _INTERPRET_ERROR("Expected expression after control keyword", p_token); + } + } + break; + case TT_WHILE: + case TT_UNTIL: + { + TokenType tt = p_interpret->tt; + List *p_list_expr = list_new(), *p_list_block = list_new(); + _Bool b_flag = true; + + _NEXT + + _expression_get(p_interpret, p_list_expr); + _block_get(p_interpret, p_list_block); + Token *p_token_backup = p_interpret->p_token; + + do { + Stack *p_stack_backup = p_interpret->p_stack; + p_interpret->p_stack = stack_new(); + + ListIterator *p_iter_backup = p_interpret->p_iter; + p_interpret->p_iter = listiterator_new(p_list_expr); + + _NEXT + + /* Dont use if here, because we want to check the p_itnerpret->ct */ + if (_expression_(p_interpret)) { + Token *p_token_top = stack_pop(p_interpret->p_stack); + + if (p_token_top == NULL) { + printf("FOO\n"); + exit(0); + } + if (tt == TT_WHILE) { + if (convert_to_integer_get(p_token_top)) { + scope_up(p_interpret->p_scope); + interpret_subprocess(p_interpret, p_list_block); + scope_down(p_interpret->p_scope); + + } else { + b_flag = false; + } + + } else if (tt == TT_UNTIL) { + if (!convert_to_integer_get(p_token_top)) { + scope_up(p_interpret->p_scope); + interpret_subprocess(p_interpret, p_list_block); + scope_down(p_interpret->p_scope); + + } else { + b_flag = false; + } + } + + /* + switch (p_interpret->ct) { + case CONTROL_BREAK: + p_interpret->ct = CONTROL_NONE; + b_flag = false; + break; + case CONTROL_NEXT: + p_interpret->ct = CONTROL_NONE; + break; + NO_DEFAULT; + } + */ + + } else { + _INTERPRET_ERROR("Expected expression after control keyword", p_token); + } + + listiterator_delete(p_interpret->p_iter); + p_interpret->p_iter = p_iter_backup; + + stack_delete(p_interpret->p_stack); + p_interpret->p_stack = p_stack_backup; + + } while (b_flag); + + list_delete(p_list_expr); + list_delete(p_list_block); + p_interpret->p_token = p_token_backup; + p_interpret->tt = token_get_tt(p_token_backup); + + return (1); + } + break; + NO_DEFAULT; + } + + return (0); +} + +int +_compare(Interpret *p_interpret) { + _CHECK TRACK + + if (_sum(p_interpret)) { + _Bool b_flag = true; + + do { + switch (p_interpret->tt) { + case TT_EQ: + case TT_NEQ: + case TT_LT: + case TT_GT: + case TT_LE: + case TT_GE: + { + Token *p_token = p_interpret->p_token; + _NEXT + + if (!_sum(p_interpret)) + _INTERPRET_ERROR("Expected sum", p_interpret->p_token); + + function_process(p_interpret, p_token, p_interpret->p_stack, 2); + } + break; /* case */ + + default: + b_flag = false; + break; + + } /* switch */ + + } while (b_flag); + + return (1); + } + + return (0); +} + +int +_sum(Interpret *p_interpret) { + _CHECK TRACK + + if (_product(p_interpret)) { + _Bool b_flag = true; + + do { + switch (p_interpret->tt) { + case TT_ADD: + case TT_SUB: + { + Token *p_token = p_interpret->p_token; + _NEXT + + if (!_product(p_interpret)) + _INTERPRET_ERROR("Expected product", p_token); + + function_process(p_interpret, p_token, p_interpret->p_stack, 2); + + } + break; /* case */ + + default: + b_flag = false; + break; + + } /* switch */ + + } while (b_flag); + + return (1); + } + + return (0); +} + +int +_product(Interpret *p_interpret) { + _CHECK TRACK + + if (_product2(p_interpret)) { + _Bool b_flag = true; + + do { + switch (p_interpret->tt) { + case TT_MULT: + case TT_DIV: + { + Token *p_token = p_interpret->p_token; + _NEXT + + if (!_product2(p_interpret)) + _INTERPRET_ERROR("Expected product2", p_token); + + function_process(p_interpret, p_token, p_interpret->p_stack, 2); + + } + break; /* case */ + + default: + b_flag = false; + break; + + } /* switch */ + + } while (b_flag); + + return (1); + } + + return (0); +} + +int +_product2(Interpret *p_interpret) { + _CHECK TRACK + + if (_term(p_interpret)) { + _Bool b_flag = true; + + do { + switch (p_interpret->tt) { + case TT_ASSIGN: + { + Token *p_token = p_interpret->p_token; + Token *p_token_temp = p_interpret->p_token_prev; + _NEXT + + if (!_expression_(p_interpret)) + _INTERPRET_ERROR("Expected expression", p_token); + + p_interpret->p_token_temp = p_token_temp; + function_process(p_interpret, p_token, p_interpret->p_stack, 2); + p_interpret->p_token_temp = NULL; + + } + break; /* case */ + + default: + b_flag = false; + break; + + } /* switch */ + + } while (b_flag); + + return (1); + } + + return (0); +} + +int +_term(Interpret *p_interpret) { + _CHECK TRACK + + switch (p_interpret->tt) { + case TT_INTEGER: + case TT_DOUBLE: + case TT_STRING: + stack_push(p_interpret->p_stack, p_interpret->p_token); + _NEXT + return (1); + + case TT_IDENT: + { + if (_NEXT_TT != TT_ASSIGN) { + if (function_is_buildin(p_interpret->p_token)) { + Token *p_token = p_interpret->p_token; + Stack *p_stack = p_interpret->p_stack; + p_interpret->p_stack = stack_new(); + + if (_HAS_NEXT) { + _NEXT + if (_expression_(p_interpret)); + + } else { + _SKIP + } + + function_process_buildin(p_interpret, p_token, p_interpret->p_stack); + + stack_merge(p_stack, p_interpret->p_stack); + stack_delete(p_interpret->p_stack); + p_interpret->p_stack = p_stack; + + return (1); + + } else if (function_is_self_defined(p_interpret)) { + Token *p_token = p_interpret->p_token; + Stack *p_stack = p_interpret->p_stack; + p_interpret->p_stack = stack_new(); + + _NEXT + if (_expression_(p_interpret)); + + function_process_self_defined(p_interpret, p_token); + + if (stack_empty(p_interpret->p_stack)) { + Token *p_token = token_new_dummy(); + token_set_tt(p_token, TT_INTEGER); + token_set_ival(p_token, 0); + stack_push(p_interpret->p_stack, p_token); + } + + stack_merge(p_stack, p_interpret->p_stack); + stack_delete(p_interpret->p_stack); + p_interpret->p_stack = p_stack; + + return (1); + } + } + + /* It is not a function, it is a variable or some sort of */ + + char *c_name = token_get_val(p_interpret->p_token); + Symbol *p_symbol = scope_get(p_interpret->p_scope, c_name); + + if (p_symbol == NULL) + _INTERPRET_ERROR("No such symbol", p_interpret->p_token); + + SymbolType st = symbol_get_sym(p_symbol); + + switch (st) { + case SYM_VARIABLE: + stack_push(p_interpret->p_stack, symbol_get_val(p_symbol)); + _NEXT + return (1); + + /* Example: proc foo { foo = "Hello"; } foo; say foo; */ + case SYM_PROCEDURE: + stack_push(p_interpret->p_stack, symbol_get_val(p_symbol)); + _NEXT + return (1); + + NO_DEFAULT; + } + } + break; + case TT_DEFINED: + { + _NEXT + if (p_interpret->tt != TT_IDENT) + _INTERPRET_ERROR("Expexted identifier for 'defined'", + p_interpret->p_token); + + char *c_name = token_get_val(p_interpret->p_token); + Token *p_token = token_new_integer(0); + + if (scope_exists(p_interpret->p_scope, c_name)) + token_set_ival(p_token, 1); + + stack_push(p_interpret->p_stack, p_token); + + _NEXT; + return (1); + } + break; + + case TT_UNDEF: + { + _NEXT + if (p_interpret->tt != TT_IDENT) + _INTERPRET_ERROR("Expexted identifier for 'defined'", + p_interpret->p_token); + + char *c_name = token_get_val(p_interpret->p_token); + Token *p_token = NULL; + Symbol *p_symbol = NULL; + + if ((p_symbol = scope_remove(p_interpret->p_scope, c_name))) { + symbol_delete(p_symbol); + p_token = token_new_integer(1); + + } else { + p_token = token_new_integer(0); + } + + stack_push(p_interpret->p_stack, p_token); + + _NEXT; + return (1); + } + break; + + case TT_PARANT_L: + { + Token *p_token = p_interpret->p_token; + _NEXT + + if (_expression_(p_interpret)) { + if (p_interpret->tt != TT_PARANT_R) + _INTERPRET_ERROR("Expected ')'", p_token); + + } else { + _INTERPRET_ERROR("Expected expression", p_token); + } + } + _NEXT + return (1); + + default: + break; + } + + return (0); +} + +int +interpret_process(Interpret *p_interpret) { + p_interpret->p_iter = listiterator_new(p_interpret->p_list_token); + + _NEXT + _program(p_interpret); + + listiterator_delete(p_interpret->p_iter); + + return (1); +} + + +int +interpret_subprocess(Interpret *p_interpret, List *p_list_token) { + Interpret *p_interpret_sub = interpret_new(p_list_token, + NULL); + + p_interpret_sub->p_scope = p_interpret->p_scope; + + int i_ret = interpret_process(p_interpret_sub); + p_interpret->ct = p_interpret_sub->ct; + + interpret_delete(p_interpret_sub); + + return (i_ret); +} + +void +interpret_run(Fype *p_fype) { + Interpret *p_interpret = + interpret_new(p_fype->p_list_token, p_fype->p_hash_syms); + + interpret_process(p_interpret); + + interpret_delete(p_interpret); +} + diff --git a/src/core/interpret.h b/src/core/interpret.h new file mode 100644 index 0000000..e2f4cb7 --- /dev/null +++ b/src/core/interpret.h @@ -0,0 +1,75 @@ +/*:* + *: File: ./src/core/interpret.h + *: A simple interpreter + *: + *: WWW : http://fype.buetow.org + *: E-Mail : fype@dev.buetow.org + *: + *: Copyright (c) 2005 2006 2007 2008, Paul Buetow (http://www.pblabs.net) + *: All rights reserved. +