Files
xeus-basic/libs/basic/src/parser.c

2072 lines
49 KiB
C
Raw Normal View History

/**
* SPDX-License-Identifier: MIT
* SPDX-FileCopyrightText: 2015-2016 Johan Van den Brande
*
* @file parser.c
*/
#define _GNU_SOURCE
#include "parser.h"
#include <ctype.h>
#include <math.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "arch.h"
#include "array.h"
#include "error.h"
#include "io.h"
#include "kbhit.h"
#include "lines.h"
#include "tokenizer.h"
#include "variables.h"
char* _dummy = 0;
/*
line = [number] statement [ : statement ] CR
statement =
PRINT expression-list [ ; ]
| IF relation-expression THEN statement
| GOTO expression
| INPUT variable-list
| LET variable = expression
| GOSUB expression
| RETURN
| FOR numeric_variable '=' numeric_expression TO numeric_expression [ STEP
number ] | CLEAR | NEW | LIST | RUN | END | DIM variable "(" expression ")" |
SAVE literal_string | LOAD literal_string | DELETE literal_string | DIR | DEF
FN(X) = expression
expression-list = ( string | expression ) [, expression-list]
variable-list = variable [, variable-list]
expression = string_expression | numeric_expression
numeric_expression = ["+"|"-"] term {("+"|"-"|"OR") term} .
term = factor {( "*" | "/" | "AND" ) factor} .
factor =
func "(" expression ")"
| number
| "(" expression ")"
| variable
| relation-expression
relation-expression =
expression relation-operator expression
func =
ABS
| AND
| ATN
| COS
| EXP
| INT
| LOG
| NOT
| OR
| RND
| SGN
| SIN
| SQR
| TAN
string = literal_string | string_func "(" string_expression ")"
literal_string = '"' ... '"'
string_func =
CHR$
...
string_expression = literal_string | string_variable
variable = ( numeric_variable | string_variable | indexed_variable )
numeric_variable = A | B | C ... | X | Y | Z
string_variable = A$ | B$ | C$ ... | X$ | Y$ | Z$
indexed_variable = ( numeric_variable | string_variable ) "(" expression ")"
relation-operator = ( "<" | "<=" | "=" | ">=" | ">" )
*/
#define MAX_LINE tokenizer_string_length
typedef union {
function_0 function_0;
function_1 function_1;
function_2 function_2;
function_3 function_3;
function_4 function_4;
function_5 function_5;
} basic_function_union;
typedef struct {
token token;
basic_function_type type : 3;
size_t nr_arguments : 3;
kind kind_1 : 1;
kind kind_2 : 1;
kind kind_3 : 1;
kind kind_4 : 1;
kind kind_5 : 1;
basic_function_union function;
} basic_function;
static array* basic_tokens = NULL;
static array* basic_functions = NULL;
static token t_keyword_print;
static token t_keyword_print_short;
static token t_keyword_spc;
static token t_keyword_tab;
static token t_keyword_goto;
static token t_keyword_on;
static token t_keyword_if;
static token t_keyword_then;
static token t_keyword_gosub;
static token t_keyword_return;
static token t_keyword_list;
static token t_keyword_clear;
static token t_keyword_new;
static token t_keyword_run;
static token t_keyword_end;
static token t_keyword_stop;
static token t_keyword_for;
static token t_keyword_to;
static token t_keyword_step;
static token t_keyword_next;
static token t_keyword_rem;
static token t_keyword_dim;
static token t_keyword_data;
static token t_keyword_read;
static token t_keyword_restore;
static token t_keyword_cls;
static token t_keyword_load;
static token t_keyword_save;
static token t_keyword_delete;
static token t_keyword_dir;
static token t_op_or;
static token t_op_and;
uint16_t __line;
static char* __cursor;
static char* __memory;
static char* __stack;
static size_t __memory_size;
static size_t __stack_size;
static size_t __program_size;
static size_t __stack_p;
basic_putchar __putch = putchar;
basic_getchar __getch = getchar;
bool __RUNNING = false;
bool __EVALUATING = false;
bool __REPL = true;
bool __STOPPED = false;
typedef enum { data_state_init, data_state_find, data_state_read } data_state;
typedef struct {
uint16_t line;
char* cursor;
char* char_pointer;
data_state state : 2;
} data_pointer;
static data_pointer __data;
typedef union {
float numeric;
char* string;
} expression_value;
typedef enum { expression_type_numeric, expression_type_string } expression_type;
typedef struct {
expression_type type;
expression_value value;
} expression_result;
typedef enum { stack_frame_type_for, stack_frame_type_gosub } stack_frame_type;
typedef struct {
stack_frame_type type;
char variable_name[tokenizer_variable_length];
float end_value;
float step;
size_t line;
char* cursor;
} stack_frame_for;
typedef struct {
stack_frame_type type;
size_t line;
char* cursor;
} stack_frame_gosub;
static int basic_dispatch_function(basic_function* function, basic_type* rv);
static basic_function* find_basic_function_by_type(token sym, basic_function_type type);
static size_t get_vector(size_t* vector, size_t size);
static char* string_term(void);
int str_len(basic_type* str, basic_type* rv);
int str_asc(basic_type* str, basic_type* rv);
int str_val(basic_type* str, basic_type* rv);
int str_str(basic_type* number, basic_type* rv);
int dump(basic_type* rv);
static void move_to_next_statement(void);
typedef enum { OP_NOP, OP_LT, OP_LE, OP_EQ, OP_GE, OP_GT, OP_NE } relop;
static bool string_condition(char* left, char* right, relop op);
static bool numeric_condition(float left, float right, relop op);
static relop get_relop(void);
token sym;
void get_sym(void) { sym = tokenizer_get_next_token(); }
static void set_line(uint16_t line_number) {
__line = line_number;
char* cursor = lines_get_contents(__line);
tokenizer_char_pointer(cursor);
}
static float numeric_expression(void);
static char* string_expression(void);
void expression(expression_result* result) {
char* string = string_expression();
if (NULL != string) {
// Got string, check for relop and apply
relop op = get_relop();
if (op == OP_NOP) {
result->type = expression_type_string;
result->value.string = string;
} else {
char* string_right = string_expression();
result->type = expression_type_numeric;
result->value.numeric = string_condition(string, string_right, op);
free(string_right);
free(string);
}
} else {
result->type = expression_type_numeric;
result->value.numeric = numeric_expression();
}
}
static void expression_print(expression_result* expr) {
if (expr->type == expression_type_string) {
basic_io_print(expr->value.string);
} else if (expr->type == expression_type_numeric) {
char buffer[16];
float value = expr->value.numeric;
long ivalue = (int)value;
if (ivalue == value) {
snprintf(buffer, sizeof(buffer), "%ld", ivalue);
basic_io_print(buffer);
} else {
snprintf(buffer, sizeof(buffer), "%f", value);
basic_io_print(buffer);
}
} else {
error("UNKNOWN EXPRESSION");
}
}
static int f_abs(basic_type* n, basic_type* rv) {
rv->kind = kind_numeric;
rv->value.number = fabs(n->value.number);
return 0;
}
static int f_rnd(basic_type* n, basic_type* rv) {
rv->kind = kind_numeric;
if (n->value.number > 0) {
int random = rand();
rv->value.number = (random * 1.0) / RAND_MAX;
return 0;
}
if (n->value.number < 0) {
srand(n->value.number);
int random = rand();
rv->value.number = (random * 1.0) / RAND_MAX;
return 0;
}
time_t now;
struct tm* tm;
now = time(NULL);
tm = localtime(&now);
rv->value.number = (tm->tm_sec * 1.0) / 60;
return 0;
}
static int f_int(basic_type* n, basic_type* rv) {
rv->kind = kind_numeric;
int i = (int)n->value.number;
rv->value.number = 1.0 * i;
return 0;
}
static int f_sqr(basic_type* n, basic_type* rv) {
rv->kind = kind_numeric;
rv->value.number = (float)sqrt((double)n->value.number);
return 0;
}
static int f_sgn(basic_type* n, basic_type* rv) {
rv->kind = kind_numeric;
if (n->value.number < 0) {
rv->value.number = -1.0;
} else if (n->value.number > 0) {
rv->value.number = 1.0;
} else {
rv->value.number = 0.0;
}
return 0;
}
static int f_not(basic_type* n, basic_type* rv) {
rv->kind = kind_numeric;
rv->value.number = (float)(~(int)n->value.number);
return 0;
}
static int f_sin(basic_type* n, basic_type* rv) {
rv->kind = kind_numeric;
rv->value.number = sinf(n->value.number);
return 0;
}
static int f_cos(basic_type* n, basic_type* rv) {
rv->kind = kind_numeric;
rv->value.number = cosf(n->value.number);
return 0;
}
static int f_tan(basic_type* n, basic_type* rv) {
rv->kind = kind_numeric;
rv->value.number = tanf(n->value.number);
return 0;
}
static int f_log(basic_type* n, basic_type* rv) {
rv->kind = kind_numeric;
rv->value.number = logf(n->value.number);
return 0;
}
static int f_exp(basic_type* n, basic_type* rv) {
rv->kind = kind_numeric;
rv->value.number = expf(n->value.number);
return 0;
}
static int f_pow(basic_type* x, basic_type* y, basic_type* rv) {
rv->kind = kind_numeric;
rv->value.number = powf(x->value.number, y->value.number);
return 0;
}
static int f_atn(basic_type* n, basic_type* rv) {
rv->kind = kind_numeric;
rv->value.number = atanf(n->value.number);
return 0;
}
static float _or(float a, float b) { return (float)((int)a | (int)b); }
static float _and(float a, float b) { return (float)((int)a & (int)b); }
static int str_chr(basic_type* n, basic_type* rv) {
rv->kind = kind_string;
char* chr;
asprintf(&chr, "%c", (int)n->value.number);
rv->value.string = chr;
rv->mallocd = true;
return 0;
}
static int str_mid(basic_type* str, basic_type* start, basic_type* length, basic_type* rv) {
rv->kind = kind_string;
char* source = str->value.string;
int _start = (int)start->value.number - 1;
if (_start > strlen(source)) _start = strlen(source);
int _length;
if (length->empty) {
_length = strlen(source) - _start;
} else {
_length = (int)length->value.number;
if (_length + _start > strlen(source)) _length = strlen(source) - _start;
}
char* string = strdup(&source[_start]);
string[_length] = '\0';
rv->value.string = string;
rv->mallocd = true;
return 0;
}
static int str_right(basic_type* str, basic_type* length, basic_type* rv) {
rv->kind = kind_string;
char* source = str->value.string;
rv->value.string = strdup(&source[strlen(source) - (int)length->value.number]);
rv->mallocd = true;
return 0;
}
static int str_left(basic_type* str, basic_type* length, basic_type* rv) {
rv->kind = kind_string;
rv->value.string = strdup(str->value.string);
rv->value.string[(int)length->value.number] = '\0';
rv->mallocd = true;
return 0;
}
bool accept(token t) {
if (t == sym) {
get_sym();
return true;
}
return false;
}
static bool expect(token t) {
if (accept(t)) {
return true;
}
error("UNEXPECTED SYMBOL");
return false;
}
static float factor(void);
static float numeric_factor(void) {
float number = 0;
basic_function* bf;
if ((bf = find_basic_function_by_type(sym, basic_function_type_numeric)) != NULL) {
basic_type rv;
basic_dispatch_function(bf, &rv);
if (rv.kind != kind_numeric) {
error("EXPECTED NUMERIC FACTOR");
}
number = rv.value.number;
} else if (sym == T_NUMBER) {
number = tokenizer_get_number();
accept(T_NUMBER);
} else if (sym == T_VARIABLE_NUMBER) {
char var_name[tokenizer_variable_length];
tokenizer_get_variable_name(var_name);
get_sym();
if (sym == T_LEFT_BANANA) {
size_t l = strlen(var_name);
var_name[l] = '(';
var_name[l + 1] = '\0';
accept(T_LEFT_BANANA);
size_t vector[5];
get_vector(vector, 5);
number = variable_array_get_numeric(var_name, vector);
expect(T_RIGHT_BANANA);
} else {
number = variable_get_numeric(var_name);
accept(T_VARIABLE_NUMBER);
}
} else if (accept(T_LEFT_BANANA)) {
number = numeric_expression();
expect(T_RIGHT_BANANA);
} else {
error("FACTOR SYNTAX ERROR");
get_sym();
}
relop op = get_relop();
if (op != OP_NOP) {
float right_number = factor();
number = numeric_condition(number, right_number, op);
}
return number;
}
static float factor(void) {
if (sym == T_STRING || sym == T_VARIABLE_STRING) {
char* s1 = string_term();
relop op = get_relop();
if (op == OP_NOP) {
free(s1);
error("EXPECTED RELOP");
return 0;
}
char* s2 = string_term();
float r = string_condition(s1, s2, op);
free(s2);
free(s1);
return r;
} else {
return numeric_factor();
}
}
static float term(void) {
float f1 = factor();
while (sym == T_MULTIPLY || sym == T_DIVIDE || sym == t_op_and) {
token operator= sym;
get_sym();
float f2 = factor();
switch (operator) {
case T_MULTIPLY:
f1 = f1 * f2;
break;
case T_DIVIDE:
f1 = f1 / f2;
break;
default:
if (operator== t_op_and) {
f1 = _and(f1, f2);
} else {
error("TERM SYNTAX ERROR");
}
}
}
return f1;
}
static float numeric_expression(void) {
token operator= T_PLUS;
if (sym == T_PLUS || sym == T_MINUS) {
operator= sym;
get_sym();
}
float t1 = term();
if (operator== T_MINUS) {
t1 = -1 * t1;
}
while (sym == T_PLUS || sym == T_MINUS || sym == t_op_or) {
operator= sym;
get_sym();
float t2 = term();
switch (operator) {
case T_PLUS:
t1 = t1 + t2;
break;
case T_MINUS:
t1 = t1 - t2;
break;
default:
if (operator== t_op_or) {
t1 = _or(t1, t2);
} else {
error("EXPRESSION SYNTAX ERROR");
}
}
}
return t1;
}
static void ready(void) {
if (__REPL) {
puts("READY.");
}
}
static void list_out(uint16_t number, char* contents) {
char buffer[tokenizer_string_length];
snprintf(buffer, sizeof(buffer), "%d %s\n", number, contents);
basic_io_print(buffer);
}
static int do_list(basic_type* rv) {
uint16_t start = 0;
uint16_t end = 0;
accept(t_keyword_list);
if (sym == T_NUMBER) {
start = (uint16_t)tokenizer_get_number();
accept(T_NUMBER);
if (sym == T_MINUS) {
accept(T_MINUS);
if (sym == T_NUMBER) {
end = (uint16_t)tokenizer_get_number();
accept(T_NUMBER);
}
}
}
lines_list(start, end, list_out);
ready();
return 0;
}
static int do_clear(basic_type* rv) {
accept(t_keyword_clear);
lines_clear();
ready();
return 0;
}
static char* string_term(void) {
char* string = NULL;
char var_name[tokenizer_variable_length];
switch (sym) {
case T_STRING:
string = strdup(tokenizer_get_string());
accept(T_STRING);
break;
case T_VARIABLE_STRING:
tokenizer_get_variable_name(var_name);
get_sym();
if (sym == T_LEFT_BANANA) {
size_t l = strlen(var_name);
var_name[l] = '(';
var_name[l + 1] = '\0';
// printf("name: %s\n", var_name);
accept(T_LEFT_BANANA);
size_t vector[5];
get_vector(vector, 5);
string = strdup(variable_array_get_string(var_name, vector));
if (string == NULL) string = _dummy;
expect(T_RIGHT_BANANA);
} else {
string = strdup(variable_get_string(var_name));
accept(T_VARIABLE_STRING);
}
break;
default: {
basic_function* bf = find_basic_function_by_type(sym, basic_function_type_string);
if (bf != NULL) {
basic_type rv;
basic_dispatch_function(bf, &rv);
if (rv.kind != kind_string) {
error("EXPECTED STRING TERM");
}
string = strdup(rv.value.string);
if (rv.mallocd == true) free(rv.value.string);
}
} break;
}
return string;
}
static char* string_expression(void) {
char* s1 = string_term();
while (sym == T_PLUS) {
accept(T_PLUS);
char* s2 = string_term();
size_t len = strlen(s1) + strlen(s2) + 1;
s1 = realloc(s1, len);
s1 = strcat(s1, s2);
free(s2);
}
return s1;
}
static int do_print(basic_type* rv) {
accept(t_keyword_print);
accept(t_keyword_print_short);
if (sym == T_EOF || sym == T_COLON) // Just a print stm
{
__putch('\n');
} else {
while (sym != T_EOF && sym != T_COLON) {
basic_function* bf = find_basic_function_by_type(sym, basic_function_type_print);
if (bf != NULL) {
basic_type rv;
basic_dispatch_function(bf, &rv);
} else {
expression_result expr;
expression(&expr);
expression_print(&expr);
if (expr.type == expression_type_string) {
if (expr.value.string != _dummy) free(expr.value.string);
}
}
if (sym == T_SEMICOLON) {
accept(T_SEMICOLON);
} else if (sym == T_COMMA) {
accept(T_COMMA);
__putch('\t');
} else {
__putch('\n');
}
}
}
fflush(stdout);
return 0;
}
static int do_spc(basic_type* n, basic_type* rv) {
for (size_t i = 0; i < n->value.number; i++) {
__putch(' ');
}
rv->kind = kind_numeric;
rv->value.number = 0;
return 0;
}
static int do_tab(basic_type* n, basic_type* rv) {
for (size_t i = 0; i < n->value.number; i++) {
__putch(' ');
}
rv->kind = kind_numeric;
rv->value.number = 0;
return 0;
}
static int do_cls(basic_type* rv) {
basic_io_print("\033[2J");
basic_io_print("\033[0;0H");
rv->kind = kind_numeric;
rv->value.number = 0;
return 0;
}
static int do_goto(basic_type* rv) {
accept(t_keyword_goto);
if (sym != T_NUMBER) {
error("GOTO EXPECTED NUMBER");
return 0;
}
int line_number = (int)tokenizer_get_number();
accept(T_NUMBER);
char* line = lines_get_contents(line_number);
if (line == NULL) {
error("GOTO LINE NOT FOUND");
return 0;
}
set_line(line_number);
return 0;
}
static size_t get_list(size_t* list, size_t max_size) {
size_t size = 0;
do {
if (sym == T_COMMA) {
accept(T_COMMA);
}
float n = numeric_expression();
list[size] = n;
size++;
if (size > max_size) {
error("LIST MAX SIZE");
return size;
}
} while (sym == T_COMMA);
return size;
}
static int do_on_goto(basic_type* rv) {
accept(t_keyword_on);
int index = numeric_expression();
token what = T_EOF;
if (sym == t_keyword_goto) {
what = t_keyword_goto;
} else if (sym == t_keyword_gosub) {
what = t_keyword_gosub;
} else {
error("ON WITHOUT GOTO OR GOSUB");
return 0;
}
accept(what);
size_t list[10];
size_t size = get_list(list, 10);
if (index > size) {
error("ON OUT OF BOUNDS");
return 0;
}
size_t line_number = list[index - 1];
if (what == t_keyword_goto) {
char* line = lines_get_contents(line_number);
if (line == NULL) {
error("LINE NOT FOUND");
}
set_line(line_number);
} else {
stack_frame_gosub* g;
if (__stack_p < sizeof(stack_frame_gosub)) {
error("STACK FULL");
return 0;
}
__stack_p -= sizeof(stack_frame_gosub);
g = (stack_frame_gosub*)&(__stack[__stack_p]);
g->type = stack_frame_type_gosub;
g->line = __line;
g->cursor = tokenizer_char_pointer(NULL);
set_line(line_number);
}
return 0;
}
static int do_gosub(basic_type* rv) {
accept(t_keyword_gosub);
if (sym != T_NUMBER) {
error("EXPECTED NUMBER");
return 0;
}
int line_number = (int)tokenizer_get_number();
accept(T_NUMBER);
stack_frame_gosub* g;
if (__stack_p < sizeof(stack_frame_gosub)) {
error("STACK FULL");
return 0;
}
__stack_p -= sizeof(stack_frame_gosub);
g = (stack_frame_gosub*)&(__stack[__stack_p]);
g->type = stack_frame_type_gosub;
g->line = __line;
g->cursor = tokenizer_char_pointer(NULL);
set_line(line_number);
return 0;
}
static int do_return(basic_type* rv) {
accept(t_keyword_return);
stack_frame_gosub* g;
g = (stack_frame_gosub*)&(__stack[__stack_p]);
if (g->type != stack_frame_type_gosub) {
error("EXPECTED GOSUB STACK FRAME");
return 0;
}
__line = g->line;
tokenizer_char_pointer(g->cursor);
__stack_p += sizeof(stack_frame_gosub);
return 0;
}
static int do_for(basic_type* rv) {
accept(t_keyword_for);
if (sym != T_VARIABLE_NUMBER) {
error("EXPECTED VAR");
return 0;
}
char name[tokenizer_variable_length];
tokenizer_get_variable_name(name);
get_sym();
expect(T_EQUALS);
float value = numeric_expression();
variable_set_numeric(name, value);
expect(t_keyword_to);
float end_value = numeric_expression();
float step = 1.0;
if (sym != T_EOF && sym != T_COLON) {
expect(t_keyword_step);
step = numeric_expression();
}
stack_frame_for* f;
if (__stack_p < sizeof(stack_frame_for)) {
error("STACK FULL");
return 0;
}
__stack_p -= sizeof(stack_frame_for);
f = (stack_frame_for*)&(__stack[__stack_p]);
f->type = stack_frame_type_for;
strncpy(f->variable_name, name, tokenizer_variable_length);
f->end_value = end_value;
f->step = step;
f->line = __line;
f->cursor = tokenizer_char_pointer(NULL);
return 0;
}
static int do_next(basic_type* rv) {
accept(t_keyword_next);
stack_frame_for* f;
f = (stack_frame_for*)&(__stack[__stack_p]);
if (f->type != stack_frame_type_for) {
error("EXPECTED FOR STACK FRAME");
return 0;
}
if (sym == T_VARIABLE_NUMBER) {
char var_name[tokenizer_variable_length];
tokenizer_get_variable_name(var_name);
accept(T_VARIABLE_NUMBER);
if (strcmp(var_name, f->variable_name) != 0) {
char _error[40];
snprintf(_error, sizeof(_error), "EXPECTED NEXT WITH %s, GOT %s", var_name, f->variable_name);
error(_error);
return 0;
}
}
float value = variable_get_numeric(f->variable_name) + f->step;
if ((f->step > 0 && value > f->end_value) || (f->step < 0 && value < f->end_value)) {
__stack_p += sizeof(stack_frame_for);
return 0;
}
variable_set_numeric(f->variable_name, value);
__line = f->line;
tokenizer_char_pointer(f->cursor);
return 0;
}
static int do_end(basic_type* rv) {
__RUNNING = false;
return 0;
}
static int do_rem(basic_type* rv) {
accept(t_keyword_rem);
set_line(lines_next(__line));
get_sym();
return 0;
}
static size_t get_vector(size_t* vector, size_t size) {
for (size_t i = 0; i < size; i++) {
vector[i] = 0;
}
size_t dimensions = 0;
while (sym != T_RIGHT_BANANA) {
float n = numeric_expression();
vector[dimensions] = n;
dimensions++;
if (dimensions > size) {
error("MAX DIM");
return dimensions;
}
if (sym == T_COMMA) {
accept(T_COMMA);
}
}
return dimensions;
}
static int do_dim(basic_type* rv) {
accept(t_keyword_dim);
while (sym != T_EOF && sym != T_COLON) {
if (sym == T_VARIABLE_NUMBER || sym == T_VARIABLE_STRING) {
variable_type type
= (sym == T_VARIABLE_STRING) ? variable_type_string : variable_type_numeric;
size_t vector[5];
char name[tokenizer_variable_length];
tokenizer_get_variable_name(name);
size_t l = strlen(name);
name[l] = '(';
name[l + 1] = '\0';
accept(sym);
expect(T_LEFT_BANANA);
size_t dimensions = get_vector(vector, 5);
expect(T_RIGHT_BANANA);
variable_array_init(name, type, dimensions, vector);
}
if (sym == T_COMMA) {
accept(T_COMMA);
}
}
return 0;
}
static int do_data(basic_type* rv) {
accept(t_keyword_data);
move_to_next_statement();
return 0;
}
static bool _data_find(variable_type type, value* value) {
tokenizer_init(__data.cursor);
tokenizer_char_pointer(__data.char_pointer);
while (__data.cursor) {
get_sym();
while (sym != T_EOF) {
if (sym == t_keyword_data) {
accept(t_keyword_data);
if (type == variable_type_string) {
value->string = tokenizer_get_string();
} else {
value->number = tokenizer_get_number();
}
__data.state = data_state_read;
__data.char_pointer = tokenizer_char_pointer(NULL);
return true;
}
get_sym();
}
__data.line = lines_next(__data.line);
__data.cursor = lines_get_contents(__data.line);
tokenizer_init(__data.cursor);
}
return false;
}
static bool _data_read(variable_type type, value* value) {
bool rv = false;
tokenizer_init(__data.cursor);
tokenizer_char_pointer(__data.char_pointer);
get_sym();
if (sym != T_EOF) {
accept(T_COMMA); // seperated by comma's
if (type == variable_type_string) {
value->string = tokenizer_get_string();
} else {
value->number = tokenizer_get_number();
}
__data.char_pointer = tokenizer_char_pointer(NULL);
rv = true;
} else {
__data.cursor = lines_get_contents(__data.line);
}
return rv;
}
static bool _do_data_read(variable_type type, value* value) {
char* save_pointer = tokenizer_char_pointer(NULL);
bool rv = false;
switch (__data.state) {
case data_state_init:
__data.line = lines_first();
__data.cursor = lines_get_contents(__data.line);
__data.char_pointer = tokenizer_char_pointer(NULL);
__data.state = data_state_find;
rv = _data_find(type, value);
break;
case data_state_find:
rv = _data_find(type, value);
break;
case data_state_read: {
bool data_found = _data_read(type, value);
if (data_found) {
rv = true;
} else {
rv = _data_find(type, value);
}
}
}
tokenizer_init(__cursor);
tokenizer_char_pointer(save_pointer);
return rv;
}
static int do_read(basic_type* rv) {
bool is_array = false;
size_t vector[5];
accept(t_keyword_read);
// if not initialized data_pointer, find first data statement
// while not end of variable list
// read data, put in variable
// proceed to next data statement
while (sym != T_EOF && sym != T_COLON) {
if (sym == T_VARIABLE_NUMBER || sym == T_VARIABLE_STRING) {
variable_type type
= (sym == T_VARIABLE_STRING) ? variable_type_string : variable_type_numeric;
char name[tokenizer_variable_length];
tokenizer_get_variable_name(name);
accept(sym);
if (sym == T_LEFT_BANANA) {
is_array = true;
size_t l = strlen(name);
name[l] = '(';
name[l + 1] = '\0';
accept(T_LEFT_BANANA);
get_vector(vector, 5);
expect(T_RIGHT_BANANA);
}
value v;
bool read_ok = _do_data_read(type, &v);
if (!read_ok) {
error("READ WITHOUT DATA");
return 0;
}
if (type == variable_type_string) {
if (is_array) {
variable_array_set_string(name, v.string, vector);
} else {
variable_set_string(name, v.string);
}
} else {
if (is_array) {
variable_array_set_numeric(name, v.number, vector);
} else {
variable_set_numeric(name, v.number);
}
}
}
get_sym();
accept(T_COMMA);
}
return 0;
}
static int do_restore(basic_type* rv) {
accept(t_keyword_restore);
__data.line = 0;
__data.cursor = 0;
__data.state = data_state_init;
return 0;
}
static int is_comment(const char* s) { return s[0] == '#'; }
static int is_empty(const char* s) {
while (*s != '\0') {
if (!isspace(*s)) return 0;
s++;
}
return 1;
}
// Insert '\0' behind first non space character, starting from right.
static void _trim(char* s) {
char* p = s + strlen(s) - 1; // without the '\0'
while (p >= s && isspace(*p)) {
--p;
}
*(p + 1) = '\0';
}
static void _store(char* line) {
int number;
sscanf(line, "%d", &number);
char* p = line;
while (isdigit(*p)) {
p++;
}
while (isspace(*p)) {
p++;
}
_trim(p);
printf("%d %s\n", number, p);
lines_store((uint16_t)number, p);
}
static void _load_cb(char* line, void* context) {
if (!(is_empty(line) || is_comment(line))) {
_store(line);
}
}
static int do_load(basic_type* rv) {
accept(t_keyword_load);
if (sym != T_STRING) {
error("EXPECTED LITERAL STRING");
return 0;
}
char* filename = tokenizer_get_string();
accept(T_STRING);
lines_clear();
arch_load(filename, _load_cb, NULL);
ready();
return 0;
}
typedef struct {
uint16_t number;
} _save_cb_ctx;
static uint16_t _save_cb(char** line, void* context) {
_save_cb_ctx* ctx = (_save_cb_ctx*)context;
uint16_t number = ctx->number;
ctx->number = lines_next(number);
*line = lines_get_contents(number);
return number;
}
static int do_save(basic_type* rv) {
accept(t_keyword_save);
if (sym != T_STRING) {
error("EXPECTED LITERAL STRING");
return 0;
}
char* filename = tokenizer_get_string();
accept(T_STRING);
_save_cb_ctx ctx;
ctx.number = lines_first();
arch_save(filename, _save_cb, &ctx);
ready();
return 0;
}
static int do_delete(basic_type* rv) {
accept(t_keyword_delete);
if (sym != T_STRING) {
error("EXPECTED LITERAL STRING");
return 0;
}
char* filename = tokenizer_get_string();
accept(T_STRING);
arch_delete(filename);
ready();
return 0;
}
static void _dir_cb(char* name, size_t size, bool label, void* context) {
if (label) {
printf("-- %-13s --\n", name);
} else {
printf("> %-8s : %6ld\n", name, size);
}
}
static int do_dir(basic_type* rv) {
accept(t_keyword_dir);
arch_dir(_dir_cb, NULL);
ready();
return 0;
}
// static int
// do_def_fn(basic_type* rv)
// {
// accept(t_keyword_def);
//
// if(sym != t_keyword_fn){
// error("EXPECTED FN");
// return 0;
// }
//
// // Find 'X' between '(', ')'.
//
// // Associate 'X' with the location of the expression (string pointer).
// // When 'evalled', use the string pointer to run the expression valuator.
//
// return 0;
// }
static void parse_line(void);
static bool statement(void);
static int do_run(basic_type* rv) {
__line = lines_first();
__cursor = lines_get_contents(__line);
tokenizer_init(__cursor);
__RUNNING = true;
__STOPPED = false;
while (__cursor && __RUNNING) {
get_sym();
if (sym == T_EOF) {
__line = lines_next(__line);
__cursor = lines_get_contents(__line);
if (__cursor == NULL) {
__RUNNING = false;
break;
}
tokenizer_init(__cursor);
}
parse_line();
}
ready();
return 0;
}
static relop get_relop(void) {
if (sym == T_LESS) {
accept(T_LESS);
if (sym == T_EQUALS) {
accept(T_EQUALS);
return OP_LE;
} else if (sym == T_GREATER) {
accept(T_GREATER);
return OP_NE;
}
return OP_LT;
}
if (sym == T_EQUALS) {
accept(T_EQUALS);
return OP_EQ;
}
if (sym == T_GREATER) {
accept(T_GREATER);
if (sym == T_EQUALS) {
accept(T_EQUALS);
return OP_GE;
}
return OP_GT;
}
return OP_NOP;
}
static bool numeric_condition(float left, float right, relop op) {
switch (op) {
case OP_NOP:
error("EXPECTED RELOP");
break;
case OP_LT:
return left < right;
case OP_LE:
return left <= right;
case OP_EQ:
return left == right;
case OP_GE:
return left >= right;
case OP_GT:
return left > right;
case OP_NE:
return left != right;
}
return false;
}
static bool string_condition(char* left, char* right, relop op) {
int comparison = strcmp(left, right);
switch (op) {
case OP_NOP:
error("EXPECTED RELOP");
break;
case OP_LT:
return comparison < 0;
case OP_LE:
return comparison <= 0;
case OP_EQ:
return comparison == 0;
case OP_NE:
return comparison != 0;
case OP_GE:
return comparison >= 0;
case OP_GT:
return comparison > 0;
}
return false;
}
static bool condition(expression_result* left_er, expression_result* right_er, relop op) {
if (left_er->type == expression_type_numeric) {
if (right_er->type != expression_type_numeric) {
error("EXPECTED NUMERIC RIGHT HAND TYPE");
}
return numeric_condition(left_er->value.numeric, right_er->value.numeric, op);
} else {
if (right_er->type != expression_type_string) {
error("EXPECTED STRING RIGHT HAND TYPE");
}
return string_condition(left_er->value.string, right_er->value.string, op);
;
}
}
static void move_to_next_statement(void) {
while (sym != T_EOF && sym != T_COLON) {
get_sym();
}
}
static void move_to_next_line(void) {
set_line(lines_next(__line));
get_sym();
}
static int do_if(basic_type* rv) {
expression_result left_side, right_side;
bool result;
expression(&left_side);
if (left_side.type == expression_type_string) {
relop op = get_relop();
expression(&right_side);
result = condition(&left_side, &right_side, op);
} else {
result = left_side.value.numeric == 1.0;
}
if (sym != t_keyword_then) {
error("IF WITHOUT THEN");
return 0;
}
if (result) {
get_sym();
if (sym == T_NUMBER) {
float line_number = tokenizer_get_number();
accept(T_NUMBER);
set_line(line_number);
} else {
parse_line();
}
} else {
move_to_next_line();
}
return 0;
}
static int do_let(basic_type* rv) {
bool is_array = false;
size_t vector[5];
if (sym != T_VARIABLE_NUMBER && sym != T_VARIABLE_STRING) {
error("EXPECTED VAR");
return 0;
}
char name[tokenizer_variable_length];
tokenizer_get_variable_name(name);
token var_type = sym;
get_sym();
if (sym == T_LEFT_BANANA) {
is_array = true;
size_t l = strlen(name);
name[l] = '(';
name[l + 1] = '\0';
accept(T_LEFT_BANANA);
get_vector(vector, 5);
expect(T_RIGHT_BANANA);
}
expect(T_EQUALS);
if (var_type == T_VARIABLE_NUMBER) {
float value = numeric_expression();
if (is_array) {
variable_array_set_numeric(name, value, vector);
} else {
variable_set_numeric(name, value);
}
}
if (var_type == T_VARIABLE_STRING) {
char* value = string_expression();
if (is_array) {
variable_array_set_string(name, value, vector);
} else {
variable_set_string(name, value);
}
free(value);
}
return 0;
}
static int do_input(basic_type* rv) {
bool prompt = false;
expression_result expr;
if (sym != T_VARIABLE_NUMBER && sym != T_VARIABLE_STRING) {
expression(&expr);
if (sym == T_COMMA || sym == T_SEMICOLON) {
get_sym();
} else {
error("UNEXPECTED TOKEN");
}
prompt = true;
}
if (sym != T_VARIABLE_NUMBER && sym != T_VARIABLE_STRING) {
error("EXPECTED VAR");
return 0;
}
char name[tokenizer_variable_length];
token type = sym;
if (type == T_VARIABLE_NUMBER) {
tokenizer_get_variable_name(name);
accept(T_VARIABLE_NUMBER);
}
if (type == T_VARIABLE_STRING) {
tokenizer_get_variable_name(name);
accept(T_VARIABLE_STRING);
}
if (prompt) {
expression_print(&expr);
if (expr.type == expression_type_string) {
free(expr.value.string);
}
}
char line[MAX_LINE];
basic_io_readline((prompt ? " " : "? "), line, sizeof(line));
if (type == T_VARIABLE_NUMBER) {
char* t;
float value = strtof(line, &t);
variable_set_numeric(name, value);
}
if (type == T_VARIABLE_STRING) {
variable_set_string(name, line);
}
return 0;
}
static int do_get(basic_type* rv) {
if (sym != T_VARIABLE_STRING) {
error("EXPECTED STRING VAR");
return 0;
}
char name[tokenizer_variable_length];
tokenizer_get_variable_name(name);
accept(T_VARIABLE_STRING);
char c[4] = "";
if (kbhit()) {
int ch = __getch();
if (ch == 10) {
ch = 13;
}
snprintf(c, sizeof(c), "%c", ch);
}
variable_set_string(name, c);
return 0;
}
int do_sleep(basic_type* delay, basic_type* rv) {
int milliseconds = delay->value.number;
struct timespec ts;
ts.tv_sec = milliseconds / 1000;
ts.tv_nsec = (milliseconds % 1000) * 1000000;
nanosleep(&ts, NULL);
rv->kind = kind_numeric;
rv->value.number = 0;
return 0;
}
static void parse_line(void) {
while (sym != T_EOF
//&& sym != T_COLON
) {
bool ok = statement();
if (!ok) {
break;
}
}
}
static bool statement(void) {
switch (sym) {
case T_ERROR:
error("STATEMENT ERROR");
break;
case T_COLON:
accept(sym);
break;
default: {
basic_function* bf = find_basic_function_by_type(sym, basic_function_type_keyword);
if (bf != NULL) {
basic_type rv;
basic_dispatch_function(bf, &rv);
} else {
do_let(NULL);
}
} break;
}
return last_error == NULL;
}
void basic_destroy(void) {
variables_destroy();
tokenizer_free_registered_tokens();
array_destroy(basic_tokens);
array_destroy(basic_functions);
free(__stack);
free(__memory);
}
void basic_init(size_t memory_size, size_t stack_size) {
__memory = malloc(memory_size);
if (!__memory) {
error("CANNOT ALLOCATE PROGRAM SPACE");
return;
}
__memory_size = memory_size;
__program_size = __memory_size;
__stack = malloc(stack_size);
if (!__stack) {
error("CANNOT ALLOCATE STACK SPACE");
return;
}
__stack_size = stack_size;
__stack_p = __stack_size;
__line = 0;
__data.state = data_state_init;
basic_tokens = array_new(sizeof(token_entry));
basic_functions = array_new(sizeof(basic_function));
tokenizer_setup();
// Which ones do we keep for xmega if memory pressure too big? (X marks delete
// for xmega)
// BASIC keywords
t_keyword_list = register_function_0(basic_function_type_keyword, "LIST", do_list);
t_keyword_clear = register_function_0(basic_function_type_keyword, "CLEAR", do_clear); // X
t_keyword_new = register_function_0(basic_function_type_keyword, "NEW", do_clear);
t_keyword_goto = register_function_0(basic_function_type_keyword, "GOTO", do_goto);
t_keyword_on = register_function_0(basic_function_type_keyword, "ON", do_on_goto);
t_keyword_gosub = register_function_0(basic_function_type_keyword, "GOSUB", do_gosub);
t_keyword_return = register_function_0(basic_function_type_keyword, "RETURN", do_return);
t_keyword_run = register_function_0(basic_function_type_keyword, "RUN", do_run);
t_keyword_if = register_function_0(basic_function_type_keyword, "IF", do_if);
t_keyword_then = register_token("THEN");
t_keyword_for = register_function_0(basic_function_type_keyword, "FOR", do_for);
t_keyword_to = register_token("TO");
t_keyword_step = register_token("STEP");
t_keyword_next = register_function_0(basic_function_type_keyword, "NEXT", do_next);
t_keyword_end = register_function_0(basic_function_type_keyword, "END", do_end);
t_keyword_stop = register_function_0(basic_function_type_keyword, "STOP", do_end);
t_keyword_rem = register_function_0(basic_function_type_keyword, "REM", do_rem);
t_keyword_dim = register_function_0(basic_function_type_keyword, "DIM", do_dim);
t_keyword_data = register_function_0(basic_function_type_keyword, "DATA", do_data);
t_keyword_read = register_function_0(basic_function_type_keyword, "READ", do_read);
t_keyword_restore = register_function_0(basic_function_type_keyword, "RESTORE", do_restore);
t_keyword_load = register_function_0(basic_function_type_keyword, "LOAD", do_load);
t_keyword_save = register_function_0(basic_function_type_keyword, "SAVE", do_save);
t_keyword_delete = register_function_0(basic_function_type_keyword, "DELETE", do_delete);
t_keyword_dir = register_function_0(basic_function_type_keyword, "DIR", do_dir);
register_function_0(basic_function_type_keyword, "LET", do_let);
register_function_0(basic_function_type_keyword, "INPUT", do_input);
register_function_0(basic_function_type_keyword, "GET", do_get);
// LOGICAL and BINARY operators
t_op_or = register_token("OR");
t_op_and = register_token("AND");
// Output related
t_keyword_print = register_function_0(basic_function_type_keyword, "PRINT", do_print);
t_keyword_print_short = register_function_0(basic_function_type_keyword, "?", do_print);
t_keyword_spc = register_function_1(basic_function_type_print, "SPC", do_spc, kind_numeric);
t_keyword_tab = register_function_1(basic_function_type_print, "TAB", do_tab, kind_numeric);
t_keyword_cls = register_function_0(basic_function_type_keyword, "CLS", do_cls);
// BASIC functions
register_function_1(basic_function_type_numeric, "ABS", f_abs, kind_numeric);
register_function_1(basic_function_type_numeric, "SIN", f_sin, kind_numeric);
register_function_1(basic_function_type_numeric, "COS", f_cos, kind_numeric);
register_function_1(basic_function_type_numeric, "RND", f_rnd, kind_numeric);
register_function_1(basic_function_type_numeric, "INT", f_int, kind_numeric);
register_function_1(basic_function_type_numeric, "TAN", f_tan, kind_numeric);
register_function_1(basic_function_type_numeric, "SQR", f_sqr, kind_numeric);
register_function_1(basic_function_type_numeric, "SGN", f_sgn, kind_numeric);
register_function_1(basic_function_type_numeric, "LOG", f_log, kind_numeric);
register_function_1(basic_function_type_numeric, "EXP", f_exp, kind_numeric);
register_function_2(basic_function_type_numeric, "POW", f_pow, kind_numeric, kind_numeric);
register_function_1(basic_function_type_numeric, "ATN", f_atn, kind_numeric);
register_function_1(basic_function_type_numeric, "NOT", f_not, kind_numeric);
// BASIC string functions
register_function_1(basic_function_type_numeric, "LEN", str_len, kind_string);
register_function_1(basic_function_type_string, "CHR$", str_chr, kind_numeric);
register_function_3(basic_function_type_string, "MID$", str_mid, kind_string, kind_numeric,
kind_numeric);
register_function_2(basic_function_type_string, "LEFT$", str_left, kind_string, kind_numeric);
register_function_2(basic_function_type_string, "RIGHT$", str_right, kind_string, kind_numeric);
register_function_1(basic_function_type_numeric, "ASC", str_asc, kind_string);
register_function_1(basic_function_type_numeric, "VAL", str_val, kind_string);
register_function_1(basic_function_type_string, "STR$", str_str, kind_numeric);
// Special
register_function_1(basic_function_type_keyword, "SLEEP", do_sleep, kind_numeric);
// DEBUG
register_function_0(basic_function_type_keyword, "DUMP", dump);
lines_init(__memory, __program_size);
variables_init();
__data.line = 0;
__data.cursor = 0;
__data.state = data_state_init;
arch_init();
}
void basic_register_io(basic_putchar putch, basic_getchar getch) {
__putch = putch;
__getch = getch;
}
void basic_run(void) {
__REPL = false;
basic_eval("RUN");
}
void basic_eval(char* line) {
if (strlen(line) > 0 && (strlen(line) - 1) > tokenizer_string_length) {
error("LINE TOO LONG");
return;
}
char line_string[tokenizer_string_length];
strncpy(line_string, line, sizeof(line_string));
_trim(line_string);
if (is_empty(line_string) || is_comment(line_string)) {
return;
}
last_error = NULL;
tokenizer_init(line_string);
get_sym();
if (sym == T_NUMBER) {
float line_number = tokenizer_get_number();
char* line = tokenizer_char_pointer(NULL);
get_sym();
if (sym == T_EOF) {
lines_delete(line_number);
} else {
lines_store(line_number, line);
}
} else {
__EVALUATING = true;
while (__EVALUATING) {
parse_line();
accept(sym);
if (sym == T_EOF || sym == T_ERROR) __EVALUATING = false;
}
}
// printf("stack available: %" PRIu16 "\n", __stack_p);
// printf("memory available: %" PRIu16 "\n", lines_memory_available() );
}
float evaluate(char* expression_string) {
last_error = NULL;
tokenizer_init(expression_string);
get_sym();
float result = numeric_expression();
expect(T_EOF);
return result;
}
void evaluate_print(char* line) {
float result = evaluate(line);
printf("%s = %f\n", line, result);
}
const char* evaluate_last_error(void) { return last_error; }
void clear_last_error(void) { last_error = NULL; }
// - Register functions
static size_t basic_token_id = TOKEN_TYPE_END + 1000;
token register_token(char* token_name) {
token_entry token;
token.token = basic_token_id++;
token.name = token_name;
tokenizer_register_token(&token);
return token.token;
}
token register_function_0(basic_function_type type, char* keyword, function_0 function) {
token t = register_token(keyword);
basic_function bf
= {.token = t, .type = type, .nr_arguments = 0, .function.function_0 = function};
array_push(basic_functions, &bf);
return t;
}
token register_function_1(basic_function_type type, char* keyword, function_1 function, kind v1) {
token t = register_token(keyword);
basic_function bf = {
.token = t, .type = type, .nr_arguments = 1, .kind_1 = v1, .function.function_1 = function};
array_push(basic_functions, &bf);
return t;
}
token register_function_2(basic_function_type type, char* keyword, function_2 function, kind v1,
kind v2) {
token t = register_token(keyword);
basic_function bf = {.token = t,
.type = type,
.nr_arguments = 2,
.kind_1 = v1,
.kind_2 = v2,
.function.function_2 = function};
array_push(basic_functions, &bf);
return t;
}
token register_function_3(basic_function_type type, char* keyword, function_3 function, kind v1,
kind v2, kind v3) {
token t = register_token(keyword);
basic_function bf = {.token = t,
.type = type,
.nr_arguments = 3,
.kind_1 = v1,
.kind_2 = v2,
.kind_3 = v3,
.function.function_3 = function};
array_push(basic_functions, &bf);
return t;
}
token register_function_4(basic_function_type type, char* keyword, function_4 function, kind v1,
kind v2, kind v3, kind v4) {
token t = register_token(keyword);
basic_function bf = {.token = t,
.type = type,
.nr_arguments = 4,
.kind_1 = v1,
.kind_2 = v2,
.kind_3 = v3,
.kind_4 = v4,
.function.function_4 = function};
array_push(basic_functions, &bf);
return t;
}
token register_function_5(basic_function_type type, char* keyword, function_5 function, kind v1,
kind v2, kind v3, kind v4, kind v5) {
token t = register_token(keyword);
basic_function bf = {.token = t,
.type = type,
.nr_arguments = 5,
.kind_1 = v1,
.kind_2 = v2,
.kind_3 = v3,
.kind_4 = v4,
.kind_5 = v5,
.function.function_5 = function};
array_push(basic_functions, &bf);
return t;
}
static basic_function* find_basic_function_by_type(token sym, basic_function_type type) {
for (size_t i = 0; i < array_size(basic_functions); i++) {
basic_function* bf = (basic_function*)array_get(basic_functions, i);
if (bf->type == type && bf->token == sym) {
return bf;
}
}
return NULL;
}
static void get_parameter(kind k, basic_type* v) {
v->empty = false;
v->mallocd = false;
if (k == kind_string) {
char* s = string_expression();
v->kind = kind_string;
v->value.string = s;
} else {
float n = numeric_expression();
v->kind = kind_numeric;
v->value.number = n;
}
}
static kind function_kind_i(basic_function* function, int i) {
switch (i) {
case 0:
return function->kind_1;
case 1:
return function->kind_2;
case 2:
return function->kind_3;
case 3:
return function->kind_4;
case 4:
return function->kind_5;
default:
return kind_numeric;
}
}
static int basic_dispatch_function(basic_function* function, basic_type* rv) {
if (function->nr_arguments > 5) {
error("MAX ARGUMENTS");
return -1;
}
accept(sym);
if (function->nr_arguments == 0 && function->type == basic_function_type_keyword) {
function->function.function_0(rv);
return 0;
}
basic_type v[5];
expect(T_LEFT_BANANA);
int i = 0;
for (; i < function->nr_arguments; i++) {
if (sym != T_RIGHT_BANANA) {
get_parameter(function_kind_i(function, i), &(v[i]));
if (i < function->nr_arguments - 1) {
if (sym != T_COMMA) {
// Probably the rest are default parameters...
break; // break for loop
}
expect(T_COMMA);
}
}
}
// loop further, marking empty the variables
for (; i < function->nr_arguments; i++) {
v[i].empty = true;
v[i].mallocd = false;
v[i].kind = kind_numeric;
}
expect(T_RIGHT_BANANA);
rv->mallocd = false;
switch (function->nr_arguments) {
case 0:
function->function.function_0(rv);
break;
case 1:
function->function.function_1(&(v[0]), rv);
break;
case 2:
function->function.function_2(&(v[0]), &(v[1]), rv);
break;
case 3:
function->function.function_3(&(v[0]), &(v[1]), &(v[2]), rv);
break;
case 4:
function->function.function_4(&(v[0]), &(v[1]), &(v[2]), &(v[3]), rv);
break;
case 5:
function->function.function_5(&(v[0]), &(v[1]), &(v[2]), &(v[3]), &(v[4]), rv);
break;
default:
return -1;
}
for (int i = 0; i < function->nr_arguments; i++) {
if (v[i].kind == kind_string) {
free(v[i].value.string);
}
}
return 0;
}
int str_len(basic_type* str, basic_type* rv) {
rv->kind = kind_numeric;
rv->value.number = (int)strlen(str->value.string);
return 0;
}
int str_asc(basic_type* str, basic_type* rv) {
rv->kind = kind_numeric;
rv->value.number = (int)*(str->value.string);
return 0;
}
int str_val(basic_type* str, basic_type* rv) {
rv->kind = kind_numeric;
rv->value.number = atof(str->value.string);
return 0;
}
int str_str(basic_type* number, basic_type* rv) {
rv->kind = kind_string;
asprintf(&(rv->value.string), "%f", number->value.number);
rv->mallocd = true;
return 0;
}
void dump_var(variable* var, void* context) { variable_dump(var); }
int dump(basic_type* rv) {
variables_each(dump_var, NULL);
return 0;
}