interpreter overhaul, should be better

master
Clyne Sullivan 7 years ago
parent 28447df15a
commit 140a0bbecc

@ -1,23 +1,13 @@
#CC = gcc -m32
#AR = ar
CC = arm-none-eabi-gcc -mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16
AR = arm-none-eabi-ar
CFLAGS = -Wall -Wextra -Werror -pedantic \
-Wno-discarded-qualifiers \
-I. -fsigned-char -fno-builtin -ggdb
FILES = $(wildcard *.c)
OUTFILES = $(patsubst %.c, %.o, $(FILES))
all: $(OUTFILES)
@#$(CC) $(CFLAGS) *.o -o shell
@$(AR) r libinterp.a *.o
clean:
@echo " CLEAN"
@rm -f *.o shell libinterp.a
%.o: %.c
@echo " CC " $<
@$(CC) $(CFLAGS) -c $< -o $@
CFLAGS = -ggdb
CFILES = $(wildcard *.c)
all:
@echo $(CFILES)
@gcc -m32 $(CFLAGS) $(CFILES) -o shell
arm:
@mv shell.c shell.c.bak
@arm-none-eabi-gcc -mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 $(CFLAGS) -c *.c
@arm-none-eabi-ar r libinterp.a *.o
@mv shell.c.bak shell.c
@rm *.o

@ -1,24 +1,23 @@
# interpreter
This project aims to provide a very minimal scripting language for embedded systems. Many other languages already exist, such as Lua, Tcl, or BASIC; however, most implementations require certain system calls like a read() and write(), as they expect a filesystem. This interpreter aims to be as independent and portable as possible: parsing script from strings one at a time, having minimal built-in functions (so the user can define their own prints and such), and only requiring a few standard library functions.
This project aims to provide a very minimal scripting language for embedded systems. Many other languages already exist, such as Lua, Tcl, or BASIC; however, most implementations require certain system calls like read() and write(), as they expect a filesystem. This interpreter wants to be as system-independent and portable as possible: parsing script from strings one at a time, having minimal built-in functions (so the user can define their own IO calls and such), and only requiring a few standard library functions.
To use this program with your own device, you need some malloc/free implementation, and string functions like those in string.h, atoi, and snprintf. Some of these functions may become coded in so that a standard library isn't required.
To use this program with your own device, you'll need some malloc/free implementation, and a freestanding standard library. Newlib works well for this; however, functions like atoi() and snprintf() will probably need to be rewritten (if you don't have an \_sbrk defined).
Only a few commands are built in to the interpreter:
* set - set variables
* func/end - define functions
* if/end - if conditional
* do/while
* ret - return value from function
Interpreter features:
* Variable/function definition - in C and in script
* if/else and while loops
* a solve function to parse strings at runtime
Other features:
* function/variable defining in c
* expression solving
Inconvenient features:
* no local variables
* whitespace hopefully ignored
* whitespace sometimes ignored
Soon:
* error messages
Some TODO items:
* fix all memory leaks
* add better error messages
* arrays?
* maybe for loops
* for loops
This project is still in heavy development, so don't expect much. To include it in your own project, just link in parser.o and use the header files.
This project can be made for the host system (```make```) or an ARM system (```make arm```).
This project is still in heavy development, so don't expect much. To include it in your own project, just link in libinterp.a (for ARM) and use the header files.

@ -1,179 +1,124 @@
#include "builtins.h"
#include "stack.h"
#include "shelpers.h"
#include <memory.h>
#include <string.h>
int ifunc_set(interpreter *it);
int ifunc_label(interpreter *it);
int ifunc_end(interpreter *it);
int ifunc_if(interpreter *it);
int ifunc_do(interpreter *it);
int ifunc_while(interpreter *it);
int ifunc_ret(interpreter *it);
int ifunc_else(interpreter *it);
int ifunc_solve(interpreter *it);
const func_t indent_up[IUP_COUNT] = {
ifunc_if, ifunc_do, ifunc_label
};
const func_t indent_down[IDOWN_COUNT] = {
ifunc_else, ifunc_end, ifunc_while,
};
void iload_core(interpreter *interp)
{
inew_cfunc(interp, "set", ifunc_set);
inew_cfunc(interp, "func", ifunc_label);
inew_cfunc(interp, "end", ifunc_end);
inew_cfunc(interp, "if", ifunc_if);
inew_cfunc(interp, "do", ifunc_do);
inew_cfunc(interp, "while", ifunc_while);
inew_cfunc(interp, "ret", ifunc_ret);
inew_cfunc(interp, "else", ifunc_else);
inew_cfunc(interp, "solve", ifunc_solve);
}
int ifunc_solve(interpreter *it)
#include <stdlib.h>
#define IF_SIG (uint32_t)-1
#define WHILE_SIG (uint32_t)-2
#define ELSE_SIG (uint32_t)-3
#define FUNC_SIG (uint32_t)-4
int bn_set(instance *it);
int bn_if(instance *it);
int bn_else(instance *it);
int bn_end(instance *it);
int bn_while(instance *it);
int bn_func(instance *it);
int bn_solve(instance *it);
void iload_builtins(instance *it)
{
const char *expr = igetarg_string(it, 0);
int len = strlen(expr);
char *buf = (char *)malloc(len + 2);
strcpy(buf, expr);
buf[len] = ')';
buf[len + 1] = '\0';
variable *r = idoexpr(it, buf);
free(buf);
if (r == 0)
r = make_varn(0, 0.0f);
iret(it, r);
free(r);
return 0;
inew_cfunc(it, "set", bn_set);
inew_cfunc(it, "if", bn_if);
inew_cfunc(it, "else", bn_else);
inew_cfunc(it, "while", bn_while);
inew_cfunc(it, "func", bn_func);
inew_cfunc(it, "solve", bn_solve);
}
int ifunc_set(interpreter *it)
int bn_set(instance *it)
{
variable *n = igetarg(it, 0);
variable *v = igetarg(it, 1);
if (n == 0)
return -1;
if (n->valtype == STRING)
free((void *)n->value.p);
n->valtype = v->valtype;
n->value.p = v->value.p;
variable *var = igetarg(it, 0);
variable *value = igetarg(it, 1);
var->type = value->type;
var->value.p = value->value.p;
ipush(it, (uint32_t)var);
return 0;
}
int ifunc_label(interpreter *it)
int bn_if(instance *it)
{
variable *n = igetarg(it, 0);
variable *cond = (variable *)ipop(it);
uint32_t result = cond->value.p;
if (n == 0)
return -1;
ipush(it, result);
ipush(it, IF_SIG);
if (result == 0)
it->sindent = SKIP | it->indent;
ipush(it, 0);
ipush(it, 0); // need to return because stack modify
n->valtype = FUNC;
n->value.p = it->lnidx;
iskip(it);
return 0;
}
int ifunc_if(interpreter *it)
static uint32_t if_cond = 0;
int bn_else(instance *it)
{
int v = igetarg(it, 0)->value.p;
if (v == 0)
iskip(it);
void *arg = ipop(it);
ipush(it, (void *)v);
ipush(it, (void *)-1);
ipush(it, arg);
uint32_t cond = if_cond;
if (cond != 0)
it->sindent = SKIP | it->indent;
ipush(it, ELSE_SIG);
ipush(it, 0); // for ret
return 0;
}
int ifunc_end(interpreter *it)
int bn_end(instance *it)
{
if (it->stidx == 0)
return 0;
uint32_t lnidx = (uint32_t)ipop(it) + 1;
if (lnidx == 0) { // from an if, have conditional
ipop(it); // whatever
} else {
if (lnidx == (uint32_t)-1) {
// script-func call
lnidx = (uint32_t)ipop(it);
it->indent = (uint32_t)ipop(it);
}
it->lnidx = lnidx;
uint32_t sig = ipop(it);
if (sig == IF_SIG) {
if_cond = ipop(it);
} else if (sig == WHILE_SIG) {
uint32_t lnidx = ipop(it);
if (lnidx != (int32_t)-1)
it->lnidx = lnidx - 1;
} else if (sig == CALL_SIG) {
it->lnidx = ipop(it);
it->indent++;
}
return 0;
}
int ifunc_else(interpreter *it)
int bn_while(instance *it)
{
if (it->stidx == 0)
return 0;
variable *cond = (variable *)ipop(it);
uint32_t result = cond->value.p;
ipop(it); // the -1
int cond = (int)ipop(it);
it->indent++;
if (cond != 0)
iskip(it);
// otherwise it's whatever?
if (result == 0) {
it->sindent = SKIP | it->indent;
ipush(it, (uint32_t)-1);
} else {
ipush(it, it->lnidx);
}
ipush(it, WHILE_SIG);
ipush(it, 0);
ipush(it, (void *)-1);
ipush(it, 0); // need to ret
return 0;
}
int ifunc_do(interpreter *it)
int bn_func(instance *it)
{
ipush(it, (void *)it->lnidx);
return 0;
}
variable *f = igetarg(it, 0);
if (f == 0)
return -1;
int ifunc_while(interpreter *it)
{
int c = igetarg(it, 0)->value.p;
ipop(it);
int nidx = (int)ipop(it);
if (c != 0) {
//ipush(it, (void *)nidx);
it->lnidx = nidx - 1;
}
ipush(it, 0);
f->type = FUNC;
f->value.p = it->lnidx;
it->sindent = SKIP | it->indent;
ipush(it, FUNC_SIG);
ipush(it, 0); // for ret
return 0;
}
void iret(interpreter *it, variable *v)
int bn_solve(instance *it)
{
switch (v->valtype) {
case NUMBER:
inew_number(it, "RET", v->value.f);
break;
case STRING:
inew_string(it, "RET", (char *)v->value.p);
break;
default:
return;
break;
}
if (it->ret != 0) {
if (it->ret->valtype == STRING && it->ret->value.p != 0)
free((void *)it->ret->value.p);
it->ret->valtype = v->valtype;
it->ret->value.p = v->value.p;
it->ret = 0;
}
}
variable *s = igetarg(it, 0);
variable **ops = iparse(it, (const char *)s->value.p);
if (ops == 0)
return -1;
int ifunc_ret(interpreter *it)
{
variable *v = igetarg(it, 0);
iret(it, v);
variable *a = isolve(it, ops, 0);
free(ops);
ipush(it, (uint32_t)a);
return 0;
}

@ -3,14 +3,11 @@
#include "parser.h"
#define IUP_COUNT 3
#define IDOWN_COUNT 3
#define SKIP_SIG (uint32_t)-5
#define CALL_SIG (uint32_t)-6
void iload_core(interpreter *it);
void iload_builtins(instance *it);
void iret(interpreter *it, variable *v);
const func_t indent_up[IUP_COUNT];
const func_t indent_down[IDOWN_COUNT];
int bn_end(instance *it);
#endif // BUILTINS_H_

@ -1,8 +0,0 @@
#ifndef MEMORY_H_
#define MEMORY_H_
void *malloc(unsigned int);
void *calloc(unsigned int, unsigned int);
void free(void *);
#endif // MEMORY_H_

Binary file not shown.

236
ops.c

@ -1,117 +1,197 @@
#include "ops.h"
#include <stdlib.h>
#include <string.h>
void iop_add(variable *, variable *, variable *);
void iop_sub(variable *, variable *, variable *);
void iop_mult(variable *, variable *, variable *);
void iop_div(variable *, variable *, variable *);
void iop_and(variable *, variable *, variable *);
void iop_or(variable *, variable *, variable *);
void iop_xor(variable *, variable *, variable *);
void iop_shr(variable *, variable *, variable *);
void iop_shl(variable *, variable *, variable *);
void iop_eq(variable *, variable *, variable *);
void iop_lt(variable *, variable *, variable *);
void iop_gt(variable *, variable *, variable *);
void iop_lte(variable *, variable *, variable *);
void iop_gte(variable *, variable *, variable *);
void iop_ne(variable *, variable *, variable *);
void iop_mod(variable *, variable *, variable *);
char *iops[IOPS_COUNT] = {
"*", "/", "%", "+", "-", "<<", ">>", "<=",
"<", ">=", ">", "==", "!=", "&", "^", "|"
#define OP_DEF(o) int op_##o(variable *r, variable *a, variable *b)
#define OP_VAR(o) {0, OPERATOR, 0, {.p = (uint32_t)op_##o}}
#define OP_NONE {0, OPERATOR, 0, {.p = 0x0BADCAFE}}
extern char *strclone(const char *s);
OP_DEF(mul);
OP_DEF(div);
OP_DEF(mod);
OP_DEF(add);
OP_DEF(sub);
OP_DEF(shl);
OP_DEF(shr);
OP_DEF(lte);
OP_DEF(lt);
OP_DEF(gte);
OP_DEF(gt);
OP_DEF(eq);
OP_DEF(ne);
OP_DEF(and);
OP_DEF(xor);
OP_DEF(or);
OP_DEF(set);
variable opvars[] = {
OP_VAR(mul), OP_VAR(div), OP_VAR(mod), OP_NONE,
OP_VAR(add), OP_VAR(sub), OP_VAR(shl), OP_VAR(shr),
OP_VAR(lte), OP_VAR(lt), OP_VAR(gte), OP_VAR(gt),
OP_VAR(eq), OP_VAR(ne), OP_VAR(and), OP_VAR(xor),
OP_VAR(or), OP_VAR(set)
};
operation_t iopfuncs[IOPS_COUNT] = {
iop_mult, iop_div, iop_mod, iop_add, iop_sub,
iop_shl, iop_shr, iop_lte, iop_lt, iop_gte,
iop_gt, iop_eq, iop_ne, iop_and, iop_xor,
iop_or
const char *opnames[] = {
"*", "/", "%", 0,
"+", "-", "<<", ">>",
"<=", "<", ">=", ">",
"==", "!=", "&", "^",
"|", "="
};
void iop_add(variable *r, variable *a, variable *b)
{
r->value.f = a->value.f + b->value.f;
}
void iop_sub(variable *r, variable *a, variable *b)
{
r->value.f = a->value.f - b->value.f;
}
void iop_mult(variable *r, variable *a, variable *b)
OP_DEF(mul)
{
if (a->type != NUMBER || b->type != NUMBER)
return -1;
r->type = NUMBER;
r->value.f = a->value.f * b->value.f;
return 0;
}
void iop_div(variable *r, variable *a, variable *b)
OP_DEF(div)
{
if (a->type != NUMBER || b->type != NUMBER)
return -1;
r->type = NUMBER;
r->value.f = a->value.f / b->value.f;
return 0;
}
void iop_and(variable *r, variable *a, variable *b)
OP_DEF(mod)
{
r->value.f = (float)((int)a->value.f & (int)b->value.f);
if (a->type != NUMBER || b->type != NUMBER)
return -1;
r->type = NUMBER;
r->value.f = (int)a->value.f % (int)b->value.f;
return 0;
}
void iop_or(variable *r, variable *a, variable *b)
OP_DEF(add)
{
r->value.f = (float)((int)a->value.f | (int)b->value.f);
if (a->type != NUMBER || b->type != NUMBER)
return -1;
r->type = NUMBER;
r->value.f = a->value.f + b->value.f;
return 0;
}
void iop_xor(variable *r, variable *a, variable *b)
OP_DEF(sub)
{
r->value.f = (float)((int)a->value.f ^ (int)b->value.f);
if (a->type != NUMBER || b->type != NUMBER)
return -1;
r->type = NUMBER;
r->value.f = a->value.f - b->value.f;
return 0;
}
void iop_shr(variable *r, variable *a, variable *b)
OP_DEF(shl)
{
r->value.f = (float)((int)a->value.f >> (int)b->value.f);
if (a->type != NUMBER || b->type != NUMBER)
return -1;
r->type = NUMBER;
r->value.f = (int)a->value.f << (int)b->value.f;
return 0;
}
void iop_shl(variable *r, variable *a, variable *b)
OP_DEF(shr)
{
r->value.f = (float)((int)a->value.f << (int)b->value.f);
if (a->type != NUMBER || b->type != NUMBER)
return -1;
r->type = NUMBER;
r->value.f = (int)a->value.f >> (int)b->value.f;
return 0;
}
void iop_eq(variable *r, variable *a, variable *b)
OP_DEF(lte)
{
if (a->valtype == STRING && b->valtype == STRING)
r->value.f = (float)!strcmp((char *)a->value.p, (char *)b->value.p);
else
r->value.f = a->value.f == b->value.f;
if (a->type != NUMBER || b->type != NUMBER)
return -1;
r->type = NUMBER;
r->value.f = a->value.f <= b->value.f;
return 0;
}
void iop_lt(variable *r, variable *a, variable *b)
OP_DEF(lt)
{
if (a->type != NUMBER || b->type != NUMBER)
return -1;
r->type = NUMBER;
r->value.f = a->value.f < b->value.f;
return 0;
}
void iop_gt(variable *r, variable *a, variable *b)
OP_DEF(gte)
{
r->value.f = a->value.f > b->value.f;
if (a->type != NUMBER || b->type != NUMBER)
return -1;
r->type = NUMBER;
r->value.f = a->value.f >= b->value.f;
return 0;
}
void iop_lte(variable *r, variable *a, variable *b)
OP_DEF(gt)
{
r->value.f = a->value.f <= b->value.f;
if (a->type != NUMBER || b->type != NUMBER)
return -1;
r->type = NUMBER;
r->value.f = a->value.f > b->value.f;
return 0;
}
void iop_gte(variable *r, variable *a, variable *b)
OP_DEF(eq)
{
r->value.f = a->value.f >= b->value.f;
}
r->type = NUMBER;
if (a->type == NUMBER && b->type == NUMBER)
r->value.f = a->value.f == b->value.f;
else if (a->type == STRING && b->type == STRING)
r->value.f = !strcmp((const char *)a->value.p, (const char *)b->value.p);
else
return -1;
void iop_ne(variable *r, variable *a, variable *b)
{
r->value.f = a->value.f != b->value.f;
return 0;
}
void iop_mod(variable *r, variable *a, variable *b)
OP_DEF(ne)
{
r->value.f = (float)((int)a->value.f % (int)b->value.f);
if (a->type != NUMBER || b->type != NUMBER)
return -1;
r->type = NUMBER;
r->value.f = a->value.f != b->value.f;
return 0;
}
OP_DEF(and)
{
if (a->type != NUMBER || b->type != NUMBER)
return -1;
r->type = NUMBER;
r->value.f = (int)a->value.f & (int)b->value.f;
return 0;
}
OP_DEF(xor)
{
if (a->type != NUMBER || b->type != NUMBER)
return -1;
r->type = NUMBER;
r->value.f = (int)a->value.f ^ (int)b->value.f;
return 0;
}
OP_DEF(or)
{
if (a->type != NUMBER || b->type != NUMBER)
return -1;
r->type = NUMBER;
r->value.f = (int)a->value.f | (int)b->value.f;
return 0;
}
OP_DEF(set)
{
if (b->type == NUMBER) {
a->type = NUMBER;
a->value.f = b->value.f;
r->type = NUMBER;
r->value.f = a->value.f;
} else if (b->type == STRING) {
a->type = STRING;
if (a->value.p != 0)
free((void *)a->value.p);
a->value.p = (uint32_t)strclone((char *)b->value.p);
r->type = STRING;
r->value.p = (uint32_t)strclone((char *)a->value.p);
} else {
return -1;
}
return 0;
}

11
ops.h

@ -1,13 +1,14 @@
#ifndef OPS_H_
#define OPS_H_
#include "parser.h"
#include "variable.h"
#define IOPS_COUNT 16
#define OPS_COUNT 18
#define OP_MAGIC 0xCAFE3900
typedef void (*operation_t)(variable *, variable *, variable *);
typedef int (*opfunc_t)(variable *, variable *, variable *);
extern char *iops[IOPS_COUNT];
extern operation_t iopfuncs[IOPS_COUNT];
extern variable opvars[];
extern const char *opnames[];
#endif // OPS_H_

@ -1,478 +1,486 @@
#include <parser.h>
#include "parser.h"
#include "shelpers.h"
#include "builtins.h"
#include "stack.h"
#include "ops.h"
#include <ctype.h>
#include <stdlib.h>
#include <memory.h>
#include <stdio.h>
#include <string.h>
#define MAX_VARS 100
#define MAX_STACK 32
#define MAX_VARS 256
#define MAX_STACK 64
#define MAX_LINES 1000
void iinit(interpreter *interp)
char *strnclone(const char *s, size_t c)
{
interp->vars = (variable *)calloc(MAX_VARS, sizeof(variable));
interp->vnames = (char **)calloc(MAX_VARS, sizeof(char *));
interp->stack = (stack_t *)calloc(MAX_STACK, sizeof(stack_t));
interp->stidx = 0;
interp->lines = (variable ***)calloc(MAX_LINES, sizeof(variable **));
interp->lnidx = 0;
interp->indent = 0;
interp->sindent = 0;
interp->ret = 0;
iload_core(interp);
char *b = strncpy((char *)malloc(c + 1), s, c);
b[c] = '\0';
return b;
}
void iend(interpreter *it)
char *strclone(const char *s)
{
for (unsigned int i = 0; i < MAX_VARS; i++) {
if (it->vars[i].used == 1) {
if (it->vars[i].valtype == STRING ||
it->vars[i].valtype == EXPR)
free((void *)it->vars[i].value.p);
free(it->vnames[i]);
}
}
for (unsigned int i = 0; i < MAX_LINES; i++) {
if (it->lines[i] != 0) {
for (unsigned int j = 0; (int32_t)it->lines[i][j] > 0; j++) {
switch (it->lines[i][j]->valtype) {
case STRING:
if (!it->lines[i][j]->used)
free(it->lines[i][j]);
break;
case EXPR:
free((void *)it->lines[i][j]->value.p);
free(it->lines[i][j]);
break;
case NUMBER:
if (!it->lines[i][j]->used)
free(it->lines[i][j]);
break;
}
}
return strnclone(s, strlen(s));
}
char *fixstring(const char *s)
{
char *n = malloc(strlen(s) + 1 - 2);
int j = 0;
for (int i = 1; s[i] != '\"'; i++, j++) {
if (s[i] == '\\') {
if (s[i + 1] == 'n')
n[j] = '\n';
i++;
} else {
n[j] = s[i];
}
free(it->lines[i]);
}
n[j] = '\0';
return n;
}
void itryfree(variable *v)
{
if (v == 0 || v->tmp == 0)
return;
if (v->type == STRING)
free((void *)v->value.p);
free(v);
}
instance *inewinstance(void)
{
instance *it = (instance *)malloc(sizeof(instance));
it->vars = (variable *)calloc(MAX_VARS, sizeof(variable));
it->names = (char **)calloc(MAX_VARS, sizeof(char *));
it->stack = (uint32_t *)malloc(MAX_STACK * sizeof(uint32_t));
it->stidx = 0;
it->lines = (char **)calloc(MAX_LINES, sizeof(char *));
it->lnidx = 0;
it->ret = 0;
it->indent = 0;
it->sindent = 0;
iload_builtins(it);
return it;
}
void idelinstance(instance *it)
{
free(it->vars);
free(it->vnames);
for (uint32_t i = 0; i < MAX_VARS; i++)
free(it->names[i]);
free(it->names);
free(it->stack);
for (uint32_t i = 0; i < MAX_VARS; i++)
free(it->lines[i]);
free(it->lines);
itryfree(it->ret);
free(it);
}
void iskip(interpreter *it)
void ipush(instance *it, uint32_t v)
{
if (!(it->sindent & SKIP))
it->sindent = it->indent | SKIP;
it->stack[it->stidx++] = v;
}
variable *interpreter_get_variable(interpreter *interp, const char *name)
uint32_t ipop(instance *it)
{
for (uint32_t i = 0; i < MAX_VARS; i++) {
if (!interp->vars[i].used) {
variable *v = make_vars(&interp->vars[i], 0);
v->used = 1;
interp->vnames[i] = strclone(name);
return v;
} else if (interp->vnames[i] != 0 && !strcmp(interp->vnames[i], name)) {
return &interp->vars[i];
}
}
return 0;
return it->stack[--it->stidx];
}
char *interpreter_get_name(interpreter *interp, variable *v)
void ipopm(instance *it, uint32_t count)
{
for (uint32_t i = 0; i < MAX_VARS; i++) {
if (v == &interp->vars[i])
return interp->vnames[i];
}
return "(undefined)";
it->stidx -= count;
}
variable *inew_string(interpreter *interp, const char *name, const char *value)
variable *igetarg(instance *it, uint32_t n)
{
variable *v = interpreter_get_variable(interp, name);
if (v != 0) {
if (v->valtype == STRING && v->value.p != 0)
free((void *)v->value.p);
v->valtype = STRING;
v->value.p = (uint32_t)strclone(value);
}
return (variable *)it->stack[it->stidx - n - 1];
}
variable *igetvar(instance *it, const char *name);
void inew_cfunc(instance *it, const char *name, func_t func)
{
variable *v = igetvar(it, name);
v->type = CFUNC;
v->value.p = (uint32_t)func;
}
void inew_number(instance *it, const char *name, float f)
{
variable *v = igetvar(it, name);
v->type = NUMBER;
v->value.f = f;
}
void inew_string(instance *it, const char *name, const char *s)
{
variable *v = igetvar(it, name);
v->type = STRING;
v->value.p = (uint32_t)strclone(s);
}
variable *varclone(variable *n)
{
variable *v = (variable *)malloc(sizeof(variable));
v->tmp = 1;
v->type = n->type;
if (n->type == STRING)
v->value.p = (uint32_t)strclone((char *)n->value.p);
else
v->value.p = n->value.p;
return v;
}
variable *inew_number(interpreter *interp, const char *name, float value)
variable *make_varf(variable *v, float f)
{
variable *v = interpreter_get_variable(interp, name);
if (v != 0) {
v->valtype = NUMBER;
v->value.f = value;
if (v == 0) {
v = (variable *)malloc(sizeof(variable));
v->tmp = 1;
}
v->type = NUMBER;
v->value.f = f;
return v;
}
variable *inew_cfunc(interpreter *interp, const char *name, func_t func)
variable *make_vars(variable *v, const char *s)
{
variable *v = interpreter_get_variable(interp, name);
if (v != 0) {
v->fromc = 1;
v->valtype = FUNC;
v->value.p = (uint32_t)func;
if (v == 0) {
v = (variable *)malloc(sizeof(variable));
v->tmp = 1;
}
v->type = STRING;
v->value.p = (uint32_t)strclone(s);
return v;
}
variable *make_var(interpreter *interp, const char *line, uint32_t *next)
variable *make_num(const char *text)
{
if (line[0] == '\"') { // string literal
uint32_t end = 1;
while (!eol(line[end])) {
if (line[end] == '\"'/* && line[end - 1] != '\\'*/) {
if (!eot(line[end + 1]))
int decimal = -1;
char valid = 0;
int i = 0;
if (text[0] == '-')
i++;
do {
if (text[i] == '.') {
if (decimal >= 0) {
valid = 0;
break;
}
decimal = i;
} else if (isdigit(text[i])) {
valid |= 1;
} else {
break;
}
} while (text[++i] != '\0');
if (valid == 0)
return 0;
// TODO string breakdown
*next = end + 1;
char *str = strnclone(line + 1, end - 1);
variable *v = make_vars(0, str);
free(str);
char *buf = (char *)malloc(i + 1);
strncpy(buf, text, i);
buf[i] = '\0';
variable *v = make_varf(0, strtof(buf, 0));
free(buf);
return v;
}
variable *igetop(instance *it, const char *name)
{
for (uint32_t i = 0; i < OPS_COUNT; i++) {
if (opnames[i] != 0 && !strcmp(name, opnames[i])) {
return &opvars[i];
}
end++;
}
return 0;
} else if (line[0] == '(') { // equation literal
uint32_t end = findend(line, '(', ')');
if (eot(line[end]))
return 0;
*next = end + 1;
char *expr = strnclone(line + 1, end);
variable *v = make_vare(0, expr);
free(expr);
return v;
} else {
variable *v = make_varn(0, 0.0f);
int inc = try_number(v, line);
if (inc != 0) {
*next = inc;
return v;
}
variable *igetvar(instance *it, const char *name)
{
if (isalpha(name[0])) {
for (uint32_t i = 0; i < MAX_VARS; i++) {
if (it->names[i] == 0) {
it->names[i] = strclone(name);
// default to 0 float
return make_varf(&it->vars[i], 0.0f);
} else if (!strcmp(name, it->names[i])) {
return &it->vars[i];
}
free(v);
char *name = 0;
inc = try_variable(&name, line);
if (inc != 0) {
*next = (inc > 0) ? inc : -inc;
variable *v = interpreter_get_variable(interp, name);
free(name);
return v;
}
}
return 0;
return igetop(it, name);
}
int idoline(interpreter *interp, const char *line)
int idoline(instance *it, const char *s)
{
uint32_t ooffset = 0, offset = 0, next;
int fret = 0;
it->lines[it->lnidx] = strclone(s);
variable **ops;
loop:
ops = iparse(it, it->lines[it->lnidx]);
if (line[0] == '\0')
return 0;
skipblank(line, eol, &offset);
if (line[offset] == '#' || eol(line[offset]))
return 0;
if (it->ret != 0)
itryfree(it->ret);
it->ret = 0;
variable **linebuf = (variable **)calloc(8, sizeof(variable *));
interp->lines[interp->lnidx] = linebuf;
variable **ops = interp->lines[interp->lnidx];
if (ops == 0)
goto next;
it->ret = isolve(it, ops, 0);
// step 1 - convert to tokens
while (!eol(line[offset])) {
if (offset > 0 && line[offset] == '>') {
offset++;
skipblank(line, eol, &offset);
variable *r = make_var(interp, line + offset, &next);
ops[ooffset] = (void *)-1;
ops[ooffset + 1] = r;
offset += next;
skipblank(line, eol, &offset);
continue;
}
variable *v = make_var(interp, line + offset, &next);
ops[ooffset] = v;
if (ops[ooffset] == 0) {
fret = -4;
goto fail;
} else {
ooffset++;
offset += next;
}
skipblank(line, eol, &offset);
}
next:
free(ops);
it->lnidx++;
if (it->lines[it->lnidx] != 0)
goto loop;
// step 2 - execute
if (ooffset == 0) {
fret = -1;
goto fail;
}
return 0;
}
if (ops[0]->valtype != FUNC) {
fret = -2;
goto fail;
}
variable *isolve_(instance *it, variable **ops, uint32_t count);
variable *isolve(instance *it, variable **ops, uint32_t count)
{
if (count == 0)
for (count = 0; ops[count] != 0; count++);
if (ops[0]->fromc && ops[0]->value.p == 0) {
fret = -3;
goto fail;
for (uint32_t i = 0; i < count; i++) {
if (((uint32_t)ops[i] & OP_MAGIC) == OP_MAGIC) {
uint32_t count_ = (uint32_t)ops[i] & 0xFF;
ops[i] = isolve(it, ops + i + 1, count_);
for (uint32_t j = 1; j <= count_; j++)
ops[i + j] = 0;
}
}
if (ops[ooffset] != (void *)-1)
ops[ooffset] = 0;
return isolve_(it, ops, count);
}
loop:
for (uint8_t i = 0; i < IUP_COUNT; i++) {
if (interp->lines[interp->lnidx][0]->value.p
== (uint32_t)indent_up[i]) {
interp->indent++;
goto cont;
}
}
for (uint8_t i = 0; i < IDOWN_COUNT; i++) {
if (interp->lines[interp->lnidx][0]->value.p
== (uint32_t)indent_down[i]) {
if (--interp->indent < 0) {
fret = -6;
goto fail;
}
if (interp->indent < (interp->sindent & ~(SKIP)))
interp->sindent &= ~(SKIP);
variable *isolve_(instance *it, variable **ops, uint32_t count)
{
// first, look for functions
for (uint32_t i = 0; i < count; i++) {
if (ops[i] == 0)
continue;
if (ops[i]->type == CFUNC || ops[i]->type == FUNC) {
uint32_t nargs = (uint32_t)ops[i + 1];
uint32_t start = i;
i += 2;
int32_t j;
for (j = nargs; j > 0 && i < count; i++) {
if (ops[i] != 0) {
if (ops[start]->type == CFUNC) {
it->stack[it->stidx + j - 1] = (uint32_t)ops[i];
} else {
char namebuf[6];
snprintf(namebuf, 6, "arg%d", nargs - j);
if (ops[i]->type == NUMBER)
inew_number(it, namebuf, ops[i]->value.f);
else
goto cont;
break;
}
inew_string(it, namebuf,
(const char *)ops[i]->value.p);
}
cont:
if (interp->indent > 0 && interp->sindent & SKIP)
goto norun;
ops = (variable **)malloc(8 * sizeof(variable *));
for (uint8_t i = 0; i < 8; i++)
ops[i] = interp->lines[interp->lnidx][i];
uint32_t oldLnidx = interp->lnidx;
// eval expressions
ooffset = 1;
for (; ops[ooffset] != 0 && ops[ooffset] != (void *)-1; ooffset++) {
if (ops[ooffset]->valtype == EXPR) {
char *expr = strclone((char *)ops[ooffset]->value.p);
variable *r = idoexpr(interp, expr);
ops[ooffset] = r;
free(expr);
j--;
}
}
if (j != 0)
return 0;
if (ops[ooffset] == (void *)-1)
interp->ret = ops[ooffset + 1];
if (ops[0]->fromc) {
for (uint32_t i = ooffset; --i > 0;)
ipush(interp, ops[i]);
if (ops[start]->type == CFUNC) {
func_t func = (func_t)ops[start]->value.p;
it->stidx += nargs;
int ret = ((func_t)ops[0]->value.p)(interp);
uint32_t sidx = it->stidx;
int ret = 0;
if (!(it->sindent & SKIP))
ret = func(it);
if (ret != 0)
return ret;
ipopm(interp, ooffset - 1);
return 0;
if (it->stidx > sidx)
ops[start] = (variable *)ipop(it);
else
ops[start] = 0;
ipopm(it, nargs);
} else {
char an[6];
for (uint32_t i = 1; i < ooffset; i++) {
snprintf(an, 6, "arg%d", (int)(i - 1));
switch (ops[i]->valtype) {
case STRING:
inew_string(interp, an, (char *)ops[i]->value.p);
break;
case NUMBER:
inew_number(interp, an, ops[i]->value.f);
break;
default:
break;
}
ipush(it, it->lnidx);
ipush(it, CALL_SIG);
it->lnidx = ops[start]->value.p;
}
ipush(interp, (void *)(uint32_t)interp->indent);
ipush(interp, (void *)interp->lnidx);
ipush(interp, (void *)-2); // magic
interp->lnidx = ops[0]->value.p;
interp->indent++;
ops[start + 1] = 0;
for (uint32_t j = start + 2; j < i; j++) {
itryfree(ops[j]);
ops[j] = 0;
}
if ((int32_t)interp->stidx < 0) {
interp->stidx = 0;
return -5;
}
for (uint32_t i = 1; i < ooffset; i++) {
if (ops[i] != interp->lines[oldLnidx][i]) {
if (ops[i]->valtype == STRING || ops[i]->valtype == EXPR)
free((void *)ops[i]->value.p);
free(ops[i]);
}
// next, operators
for (uint32_t j = 0; j < OPS_COUNT; j += 2) {
for (uint32_t i = 0; i < count; i++) {
if (ops[i] == 0)
continue;
if (ops[i]->type == OPERATOR) {
if (ops[i]->value.p != (uint32_t)opvars[j].value.p) {
if (ops[i]->value.p != (uint32_t)opvars[j + 1].value.p)
continue;
}
free(ops);
norun:
interp->lnidx++;
if (interp->lines[interp->lnidx] != 0)
goto loop;
opfunc_t func = (opfunc_t)ops[i]->value.p;
uint32_t aidx = i - 1;
while (ops[aidx] == 0 && aidx != 0)
aidx--;
if (ops[aidx] == 0)
return 0;
fail:
free(interp->lines[interp->lnidx]);
interp->lines[interp->lnidx] = 0;
return fret;
}
variable *idoexpr(interpreter *interp, const char *line)
{
void *ops[16];
uint32_t ooffset = 0;
uint32_t offset = 0;
// step 1 - break apart line
for (uint8_t i = 0; i < 16; i++)
ops[i] = 0;
// skip whitespace
skipblank(line, eol, &offset);
while (!eoe(line[offset])) {
if (line[offset] == '(') {
uint8_t indent = 0;
uint32_t i;
for (i = offset + 1; !eol(line[i]); i++) {
if (line[i] == '(') {
indent++;
} else if (line[i] == ')') {
if (indent == 0) {
break;
} else {
indent--;
}
}
}
if (eol(line[i]))
uint32_t bidx = i + 1;
while (ops[bidx] == 0 && ++bidx < count);
if (bidx == count)
return 0;
ops[ooffset] = idoexpr(interp, line + offset + 1);
offset = i + 1;
} else {
variable *v = make_varn(0, 0.0f);
int inc = try_number(v, line + offset);
if (inc != 0) {
ops[ooffset] = v;
offset += inc;
} else {
free(v);
char *name;
inc = try_variable(&name, line + offset);
if (inc != 0) {
v = interpreter_get_variable(interp, name);
ops[ooffset] = v;
free(name);
if (inc < 0) {
inc = -inc;
ops[ooffset + 2] = v;
ops[ooffset + 1] = (void *)5; // -
ops[ooffset] = make_varn(0, 0.0f);
ooffset += 2;
}
offset += inc;
if (it->sindent & SKIP) {
itryfree(ops[aidx]);
itryfree(ops[bidx]);
ops[aidx] = 0;
} else {
variable *v = varclone(ops[aidx]);
if (func(v, ops[aidx], ops[bidx]) != 0)
return 0;
itryfree(ops[aidx]);
ops[aidx] = v;
itryfree(ops[bidx]);
}
ops[i] = 0;
ops[bidx] = 0;
}
}
}
if (ops[ooffset] == 0)
return 0;
return ops[0];
}
ooffset++;
variable **iparse(instance *it, const char *s)
{
uint32_t ooffset = 0;
size_t offset = 0;
// skip whitespace
skipblank(line, eoe, &offset);
if (eoe(line[offset]))
break;
while (isblank(s[offset]))
offset++;
if (s[offset] == '#' || s[offset] == '\0' || s[offset] == '\n')
return 0;
for (uint32_t i = 0; i < IOPS_COUNT; i++) {
int len = strlen(iops[i]);
if (!strncmp(iops[i], line + offset, len)) {
ops[ooffset] = (void *)(i + 1);
offset += len;
break;
variable **ops = (variable **)calloc(32, sizeof(variable *));
while (s[offset] != '\0' && s[offset] != '\n') {
if (isalpha(s[offset])) {
size_t end = offset + 1;
while (isalnum(s[end]))
end++;
char *name = strnclone(s + offset, end - offset);
ops[ooffset++] = igetvar(it, name);
free(name);
while (isblank(s[end]))
end++;
if (s[end] == '(') {
uint32_t argidx = ooffset;
uint32_t argcount = 0;
ooffset++;
end++;
for (int last = end, c = 0; c >= 0; end++) {
if (s[end] == '(')
c++;
if (c == 0 && last != end && (s[end] == ',' || s[end] == ')')) {
argcount++;
char *arg = strnclone(s + last, end - last);
uint32_t parenidx = ooffset;
ooffset++;
variable **moreops = iparse(it, arg);
uint32_t count = 0;
if (moreops != 0) {
for (uint32_t i = 0; moreops[i] != 0; count++, i++)
ops[ooffset++] = moreops[i];
free(moreops);
}
free(arg);
ops[parenidx] = (variable *)(OP_MAGIC | count);
last = end + 1;
}
if (ops[ooffset] == 0) // implicit multiply
ops[ooffset] = (void *)1;
ooffset++;
// skip whitespace
skipblank(line, eol, &offset);
if (s[end] == ')')
c--;
}
if (ooffset % 2 == 0)
if (s[end] != '\0')
end++;
ops[argidx] = (variable *)argcount;
}
offset = end;
} else if (isdigit(s[offset])) {
size_t end = offset + 1;
while (isdigit(s[end]) || s[end] == '.')
end++;
char *word = strnclone(s + offset, end - offset);
ops[ooffset++] = make_num(word);
free(word);
offset = end;
} else if (s[offset] == '\"') {
size_t end = offset + 1;
while (s[end] != '\"')// && s[end - 1] == '\\')
end++;
end++;
char *word = strnclone(s + offset, end - offset);
char *fword = fixstring(word);
ops[ooffset++] = make_vars(0, fword);
free(word);
free(fword);
offset = end;
} else if (s[offset] == '(') {
size_t i = offset + 1;
for (int c = 0; s[i] != ')' || --c >= 0; i++) {
if (s[i] == '(')
c++;
}
i++;
char *word = strnclone(s + offset + 1, i - offset - 2);
uint32_t parenidx = ooffset;
ooffset++;
variable **moreops = iparse(it, word);
uint32_t count = 0;
if (moreops != 0) {
for (uint32_t i = 0; moreops[i] != 0; count++, i++)
ops[ooffset++] = moreops[i];
free(moreops);
}
free(word);
ops[parenidx] = (variable *)(OP_MAGIC | count);
offset = i;
} else if (!isblank(s[offset])) {
size_t end = offset + 1;
while (!isblank(s[end]) && s[end] != '\0')
end++;
char *word = strnclone(s + offset, end - offset);
// bracket?
if (!strcmp(word, "{")) {
it->indent++;
if (it->sindent & SKIP)
ipush(it, SKIP_SIG);
} else if (!strcmp(word, "}")) {
it->indent--;
if (it->indent < (it->sindent & ~(SKIP)))
it->sindent = 0;
bn_end(it);
} else {
variable *v = igetop(it, word);
if (v == 0)
return 0;
// step 2 - do operations
// for every operator, ordered by importance
for (uint32_t i = 0; i < IOPS_COUNT; i++) {
// find instances of the operation
for (uint32_t j = 1; j < ooffset; j += 2) {
// if a match
if ((uint32_t)ops[j] == i + 1) {
// find args
uint32_t ai = j - 1;
uint32_t bi = j + 1;
while (ops[ai] == 0)
ai--;
while (ops[bi] == 0)
bi++;
variable *r = (variable *)calloc(1, sizeof(variable));
iopfuncs[i](r, ops[ai], ops[bi]);
variable *v = (variable *)ops[ai];
if (!v->used)
free(v);
ops[ai] = r;
v = (variable *)ops[bi];
if (!v->used)
free(v);
ops[bi] = 0;
ops[j] = 0;
ops[ooffset++] = v;
}
free(word);
offset = end;
} else {
offset++;
}
}
variable *result = make_varn(0, ((variable *)ops[0])->value.f);
if (!((variable *)ops[0])->used)
free(ops[0]);
//for (uint32_t i = 1; i < ooffset; i += 2)
// iopfuncs[(uint32_t)ops[i] - 1](result, result, ops[i + 1]);
//for (uint32_t i = 0; i < ooffset; i += 2) {
// variable *v = (variable *)ops[i];
// if (!v->used) {
// if (v->valtype == STRING || v->valtype == EXPR)
// free((void *)v->value.p);
// free(ops[i]);
// }
//}
return result;
// mark end
ops[ooffset] = 0;
return ops;
}

@ -1,36 +1,40 @@
#ifndef PARSER_H_
#define PARSER_H_
#include <variable.h>
#include "variable.h"
typedef variable *stack_t;
#include <stdint.h>
typedef struct {
variable *vars;
char **vnames;
stack_t *stack;
char **names;
uint32_t *stack;
uint32_t stidx;
variable ***lines;
char **lines;
uint32_t lnidx;
int8_t indent;
uint8_t sindent;
variable *ret;
} interpreter;
uint8_t indent;
uint8_t sindent;
} instance;
#define SKIP (1 << 7)
typedef int (*func_t)(interpreter *);
typedef int (*func_t)(instance *);
instance *inewinstance(void);
void idelinstance(instance *it);
void iinit(interpreter *);
void iend(interpreter *);
int idoline(instance *it, const char *s);
variable **iparse(instance *it, const char *s);
variable *isolve(instance *it, variable **ops, uint32_t count);
void iskip(interpreter *);
void inew_cfunc(instance *it, const char *name, func_t func);
variable *inew_string(interpreter *, const char *, const char *);
variable *inew_number(interpreter *, const char *, float);
variable *inew_cfunc(interpreter *, const char *, func_t);
variable *make_varf(variable *v, float f);
variable *make_vars(variable *v, const char *s);
int idoline(interpreter *, const char *);
variable *idoexpr(interpreter *, const char *);
uint32_t ipop(instance *it);
void ipush(instance *it, uint32_t v);
variable *igetarg(instance *it, uint32_t n);
#endif // PARSER_H_

@ -1,7 +0,0 @@
set x 42
set eq ".a/a"
solve eq > ans
print ans
print "\n"

@ -1,27 +1,24 @@
#include <parser.h>
#include <builtins.h>
#include "stack.h"
#include <memory.h>
#include <stdio.h>
//#include <stdlib.h>
#include <string.h>
int s_put(interpreter *it)
#include "parser.h"
int print(instance *it)
{
variable *v = igetarg(it, 0);
if (v->valtype == NUMBER)
printf("%.f", v->value.f);
variable *s = igetarg(it, 0);
if (s->type == NUMBER) {
if (s->value.f == (int)s->value.f)
printf("%d\n", (int)s->value.f);
else
printf("%s", (char *)v->value.p);
printf("%.3f\n", s->value.f);
} else if (s->value.p != 0) {
printf("%s\n", (char *)s->value.p);
}
return 0;
}
int main(int argc, char **argv)
{
interpreter interp;
if (argc != 2) {
printf("Usage: %s file\n", argv[0]);
return -1;
@ -33,20 +30,23 @@ int main(int argc, char **argv)
return -1;
}
iinit(&interp);
inew_cfunc(&interp, "print", s_put);
instance *it = inewinstance();
inew_cfunc(it, "print", print);
char *line = 0;
unsigned int size;
size_t size;
int result;
while (getline(&line, &size, fp) != -1) {
*strchr(line, '\n') = '\0';
result = idoline(&interp, line);
result = idoline(it, line);
if (result != 0)
printf("Error: %d\n", result);
//if (it->ret != 0)
// printf("%s = %f\n", line, it->ret->value.f);
}
fclose(fp);
iend(&interp);
idelinstance(it);
return 0;
}

@ -1,64 +0,0 @@
#include "shelpers.h"
#include <memory.h>
#include <string.h>
char *strclone(const char *s)
{
char *clone = (char *)malloc(strlen(s) + 1);
strcpy(clone, s);
return clone;
}
char *strnclone(const char *s, uint32_t n)
{
char *clone = (char *)malloc(n + 1);
strncpy(clone, s, n);
clone[n] = '\0';
return clone;
}
uint8_t eol(int c)
{
return c == '\n' || c == '\0';
}
uint8_t eot(int c)
{
return eol(c) || c == ' ';
}
uint8_t eoe(int c)
{
return eol(c) || c == ')';
}
uint32_t findend(const char *s, char o, char c)
{
uint8_t indent = 0;
uint32_t i;
for (i = 1; !eol(s[i]); i++) {
if (s[i] == o) {
indent++;
} else if (s[i] == c) {
if (indent == 0)
break;
else
indent--;
}
}
return i;
}
void skipblank(const char *s, uint8_t (*cmp)(int), uint32_t *offset)
{
uint32_t i = *offset;
while (!cmp(s[i])) {
if (s[i] != ' ' && s[i] != '\t')
break;
i++;
}
*offset = i;
}

@ -1,62 +0,0 @@
#ifndef SHELPERS_H_
#define SHELPERS_H_
#include <stdint.h>
/**
* Clones the given string, malloc'ing a new one.
* @param s the string to clone
* @return the malloc'd copy
*/
char *strclone(const char *s);
/**
* Clones the given string until the given count.
* @param s the string to clone
* @param n the number of characters to clone
* @return the malloc'd copy
*/
char *strnclone(const char *s, uint32_t n);
/**
* Returns non-zero if the character is considered an end-of-line.
* @param c a character
* @return non-zero if eol, zero if not
*/
uint8_t eol(int c);
/**
* Returns non-zero if the character is considered an end-of-token.
* @param c a character
* @return non-zero if eot, zero if not
*/
uint8_t eot(int c);
/**
* Returns non-zero if the character is considered an end-of-expression.
* @param c a character
* @return non-zero if eoe, zero if not
*/
uint8_t eoe(int c);
/**
* Finds the matching end character in a string, e.g. matching parens.
* @param s the string to search
* @param o the starting, opening character (e.g. '(')
* @param c the end, closing character (e.g. ')')
* @return offset of the end character in the string
*/
uint32_t findend(const char *s, char o, char c);
/**
* Increments offset until the character in the string is not blank or fails
* the given comparison.
* @param s the string to use
* @param cmp a comparing function, stops search if returns true
* @param offset the variable to increment while searching
*/
void skipblank(const char *s, uint8_t (*cmp)(int), uint32_t *offset);
#endif // SHELPERS_H_

@ -1,38 +0,0 @@
#include "stack.h"
void ipush(interpreter *it, void *v)
{
it->stack[it->stidx++] = v;
}
void *ipop(interpreter *it)
{
return it->stack[--it->stidx];
}
void ipopm(interpreter *it, uint32_t count)
{
it->stidx -= count;
}
variable *igetarg(interpreter *interp, uint32_t index)
{
return interp->stack[interp->stidx - index - 1];
}
const char *igetarg_string(interpreter *interp, uint32_t index)
{
if (index >= interp->stidx)
return 0;
variable *v = igetarg(interp, index);
return (const char *)v->value.p;
}
float igetarg_number(interpreter *interp, uint32_t index)
{
if (index >= interp->stidx)
return 0;
variable *v = igetarg(interp, index);
return v->value.f;
}

@ -1,16 +0,0 @@
#ifndef STACK_H_
#define STACK_H_
#include "parser.h"
void ipush(interpreter *it, void *v);
void *ipop(interpreter *it);
void ipopm(interpreter *it, uint32_t count);
variable *igetarg(interpreter *interp, uint32_t index);
const char *igetarg_string(interpreter *interp, uint32_t index);
float igetarg_number(interpreter *interp, uint32_t index);
#define igetarg_integer(i, x) (int)igetarg_number(i, x)
#endif // STACK_H_

@ -1,9 +0,0 @@
#ifndef STDLIB_H_
#define STDLIB_H_
char *snprintf(char *buf, unsigned int max, const char *format, ...);
float strtof(const char *s, char **endptr);
int atoi(const char *);
#endif // STDLIB_H_

13
test1

@ -0,0 +1,13 @@
# test1
# arithmetic tests
# looking for proper basic function, respect for order of ops,
# and respect for parentheses
2 + 5
14 - 9
3 * 8 + 3
9 - 3 / 2
3 * (8 + 3)
(9 - 3) / 2
(4 + 5) * ((9 - 1) + 3)
5 - 3 + 4

16
test2

@ -0,0 +1,16 @@
# test2
# variable and function tests
# show variable recognition and proper c-function handling
a * 1
3 + b
set(a, 5)
a * 1
set(c, 4)
a / c
set(b, 2) set(d, 8)
d + set(e, 4)

25
test3

@ -0,0 +1,25 @@
# test3
# verify builtin functions, conditionals and such
a = 5
func(checka) {
if (a == 5) {
print("a == 5")
} else {
print("a != 5")
}
}
checka
print("Increment a...")
a = a + 1
checka
d = 0
while (d < 10) {
print(d)
d = d + 1
}

@ -0,0 +1,6 @@
# test4
# find memory leaks
x = 4
y = solve("x-2")
print(y)

@ -1,135 +0,0 @@
#include "variable.h"
#include "parser.h"
#include <ctype.h>
#include <stdlib.h>
#include <memory.h>
#include <string.h>
#include <shelpers.h>
extern int atoi(const char *);
char *fixstring(char *s)
{
char *n = malloc(strlen(s) + 1);
int j = 0;
for (int i = 0; s[i] != '\0'; i++, j++) {
if (s[i] == '\\') {
if (s[i + 1] == 'n')
n[j] = '\n';
i++;
} else {
n[j] = s[i];
}
}
n[j] = '\0';
return n;
}
variable *make_varn(variable *v, float value)
{
if (v == 0)
v = (variable *)malloc(sizeof(variable));
v->used = 0;
v->fromc = 0;
v->valtype = NUMBER;
v->value.f = value;
return v;
}
variable *make_vars(variable *v, const char *value)
{
if (v == 0)
v = (variable *)malloc(sizeof(variable));
v->used = 0;
v->fromc = 0;
v->valtype = STRING;
v->value.p = (value != 0) ? (uint32_t)fixstring(value) : 0;
return v;
}
variable *make_varf(variable *v, uint8_t fromc, uint32_t func)
{
if (v == 0)
v = (variable *)malloc(sizeof(variable));
v->used = 0;
v->fromc = fromc;
v->valtype = FUNC;
v->value.p = func;
return v;
}
variable *make_vare(variable *v, const char *expr)
{
if (v == 0)
v = (variable *)malloc(sizeof(variable));
v->used = 0;
v->fromc = 0;
v->valtype = EXPR;
v->value.p = (uint32_t)strclone(expr);
return v;
}
int try_variable(char **name, const char *text)
{
if (name == 0)
return 0;
int neg = 1;
int i = 0;
if (text[0] == '-') {
neg = -1;
i++;
}
if (!isalpha(text[i]))
return 0;
for (i++; isalnum(text[i]); i++);
int o = (neg < 0);
if (neg < 0)
i--;
*name = (char *)malloc(i + 1);
strncpy(*name, text + o, i);
(*name)[i] = '\0';
return (neg > 0) ? i : -(i + 1);
}
int try_number(variable *v, const char *text)
{
if (v == 0)
return 0;
int decimal = -1;
char valid = 0;
int i = 0;
if (text[0] == '-')
i++;
do {
if (text[i] == '.') {
if (decimal >= 0) {
valid = 0;
break;
}
decimal = i;
} else if (isdigit(text[i])) {
valid |= 1;
} else {
break;
}
} while (text[++i] != '\0');
if (valid == 0)
return 0;
char *buf = (char *)malloc(i + 1);
strncpy(buf, text, i);
buf[i] = '\0';
make_varn(v, strtof(buf, 0));
free(buf);
return i;
}

@ -4,28 +4,21 @@
#include <stdint.h>
typedef struct {
uint8_t used :1;
uint8_t fromc :1;
uint8_t valtype :4;
uint8_t tmp :1;
uint8_t type :3;
uint8_t unused :4;
union {
float f;
uint32_t p;
} value;
} variable;
enum valtype {
STRING = 0,
NUMBER,
enum VARTYPE {
NUMBER = 0,
STRING,
OPERATOR,
FUNC,
EXPR
CFUNC,
};
variable *make_varn(variable *v, float value);
variable *make_vars(variable *v, const char *s);
variable *make_varf(variable *v, uint8_t fromc, uint32_t func);
variable *make_vare(variable *v, const char *e);
int try_number(variable *v, const char *text);
int try_variable(char **name, const char *text);
#endif // VARIABLE_H_

Loading…
Cancel
Save