/*:* *: 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, Dipl.-Inf. (FH) Paul C. Buetow *: 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); int __expression_get(Interpret *p_interpret, List *p_list_block); int __array_get(Interpret *p_interpret, Token *p_token_arr); 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 _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 == NULL) 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 int i_count = 0; while (_statement(p_interpret) == 1) { if (++i_count == 50) { garbage_collect(); i_count = 0; } } return (1); } int _var_decl(Interpret *p_interpret) { _CHECK TRACK switch (p_interpret->tt) { case 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); } } default: break; } 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 __array_get(Interpret *p_interpret, Token *p_token_arr) { #ifdef DEBUG_ARRAY_GET printf("====> ARRAY\n"); #endif /* DEBUG_ARRAY_GET */ Array *p_array = p_token_arr->p_array; do { Token *p_token = p_interpret->p_token; #ifdef DEBUG_ARRAY_GET printf("Insert: "); token_print_ln(p_token); #endif /* DEBUG_ARRAY_GET */ array_unshift(p_array, p_token); token_ref_up(p_token); _NEXT } while (p_interpret->tt != TT_PARANT_AR); #ifdef DEBUG_ARRAY_GET printf("<==== ARRAY\n"); #endif /* DEBUG_ARRAY_GET */ /* Ignore TT_PARANT_AR */ _NEXT return (0); } 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) { 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_NOT: case TT_ASSIGN: case TT_LT: case TT_GT: { Token *p_token_op = p_interpret->p_token; Token *p_token_op2 = NULL; _NEXT switch (p_interpret->tt) { case TT_NOT: case TT_ASSIGN: case TT_LT: case TT_GT: p_token_op2 = p_interpret->p_token; _NEXT default: break; } if (!_sum(p_interpret)) _INTERPRET_ERROR("Expected sum", p_interpret->p_token); function_process(p_interpret, p_token_op, p_token_op2, 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 { Token *p_token_op2 = NULL, *p_token_tmp = NULL; switch (p_interpret->tt) { case TT_DDOT: p_token_tmp = p_interpret->p_token; _NEXT case TT_ADD: case TT_SUB: case TT_AND: case TT_OR: case TT_XOR: { Token *p_token_op = p_interpret->p_token; _NEXT if (p_token_tmp != NULL) { p_token_op2 = p_token_op; p_token_op = p_token_tmp;; } if (!_product(p_interpret)) _INTERPRET_ERROR("Expected product", p_token_op); function_process(p_interpret, p_token_op, p_token_op2, 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, NULL, 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 { if (p_interpret->tt == TT_ASSIGN && IS_NOT_OPERATOR(_NEXT_TT)) { 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, NULL, p_interpret->p_stack, 2); p_interpret->p_token_temp = NULL; } else { b_flag = false; break; } /* if */ } 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: case TT_ARRAY: 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_AL: { Token *p_token = p_interpret->p_token; _NEXT Token *p_token_arr = token_new_array(ARRAY_SIZE); stack_push(p_interpret->p_stack, p_token_arr); if (__array_get(p_interpret, p_token_arr) != 0) _INTERPRET_ERROR("Array syntax error", p_token); 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); }