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
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.
* for loops
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)
#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)
{
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);
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_solve(interpreter *it)
int bn_set(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);
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_set(interpreter *it)
int bn_if(instance *it)
{
variable *n = igetarg(it, 0);
variable *v = igetarg(it, 1);
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
if (n->valtype == STRING)
free((void *)n->value.p);
n->valtype = v->valtype;
n->value.p = v->value.p;
return 0;
}
int ifunc_label(interpreter *it)
static uint32_t if_cond = 0;
int bn_else(instance *it)
{
variable *n = igetarg(it, 0);
if (n == 0)
return -1;
n->valtype = FUNC;
n->value.p = it->lnidx;
iskip(it);
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_if(interpreter *it)
int bn_end(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);
return 0;
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_end(interpreter *it)
int bn_while(instance *it)
{
if (it->stidx == 0)
return 0;
variable *cond = (variable *)ipop(it);
uint32_t result = cond->value.p;
uint32_t lnidx = (uint32_t)ipop(it) + 1;
if (lnidx == 0) { // from an if, have conditional
ipop(it); // whatever
if (result == 0) {
it->sindent = SKIP | it->indent;
ipush(it, (uint32_t)-1);
} else {
if (lnidx == (uint32_t)-1) {
// script-func call
lnidx = (uint32_t)ipop(it);
it->indent = (uint32_t)ipop(it);
}
it->lnidx = lnidx;
ipush(it, it->lnidx);
}
return 0;
}
int ifunc_else(interpreter *it)
{
if (it->stidx == 0)
return 0;
ipop(it); // the -1
int cond = (int)ipop(it);
it->indent++;
if (cond != 0)
iskip(it);
// otherwise it's whatever?
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 v;
return (variable *)it->stack[it->stidx - n - 1];
}
variable *inew_number(interpreter *interp, const char *name, float value)
variable *igetvar(instance *it, const char *name);
void inew_cfunc(instance *it, const char *name, func_t func)
{
variable *v = interpreter_get_variable(interp, name);
if (v != 0) {
v->valtype = NUMBER;
v->value.f = value;
}
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_cfunc(interpreter *interp, const char *name, func_t func)
variable *make_varf(variable *v, float f)
{
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 = NUMBER;
v->value.f = f;
return v;
}
variable *make_var(interpreter *interp, const char *line, uint32_t *next)
variable *make_vars(variable *v, const char *s)
{
if (line[0] == '\"') { // string literal
uint32_t end = 1;
while (!eol(line[end])) {
if (line[end] == '\"'/* && line[end - 1] != '\\'*/) {
if (!eot(line[end + 1]))
return 0;
// TODO string breakdown
*next = end + 1;
char *str = strnclone(line + 1, end - 1);
variable *v = make_vars(0, str);
free(str);
return v;
}
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;
}
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;
}
if (v == 0) {
v = (variable *)malloc(sizeof(variable));
v->tmp = 1;
}
return 0;
v->type = STRING;
v->value.p = (uint32_t)strclone(s);
return v;
}
int idoline(interpreter *interp, const char *line)
variable *make_num(const char *text)
{
uint32_t ooffset = 0, offset = 0, next;
int fret = 0;
if (line[0] == '\0')
return 0;
skipblank(line, eol, &offset);
if (line[offset] == '#' || eol(line[offset]))
return 0;
variable **linebuf = (variable **)calloc(8, sizeof(variable *));
interp->lines[interp->lnidx] = linebuf;
variable **ops = interp->lines[interp->lnidx];
// 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;
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 {
ooffset++;
offset += next;
break;
}
skipblank(line, eol, &offset);
}
} while (text[++i] != '\0');
// step 2 - execute
if (ooffset == 0) {
fret = -1;
goto fail;
}
if (ops[0]->valtype != FUNC) {
fret = -2;
goto fail;
}
if (valid == 0)
return 0;
if (ops[0]->fromc && ops[0]->value.p == 0) {
fret = -3;
goto fail;
}
char *buf = (char *)malloc(i + 1);
strncpy(buf, text, i);
buf[i] = '\0';
if (ops[ooffset] != (void *)-1)
ops[ooffset] = 0;
variable *v = make_varf(0, strtof(buf, 0));
free(buf);
return v;
}
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;
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];
}
}
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;
return 0;
}
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];
}
if (interp->indent < (interp->sindent & ~(SKIP)))
interp->sindent &= ~(SKIP);
else
goto cont;
break;
}
}
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);
}
}
return igetop(it, name);
}
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]);
int ret = ((func_t)ops[0]->value.p)(interp);
if (ret != 0)
return ret;
ipopm(interp, ooffset - 1);
} 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;
}
}
int idoline(instance *it, const char *s)
{
it->lines[it->lnidx] = strclone(s);
variable **ops;
loop:
ops = iparse(it, it->lines[it->lnidx]);
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++;
}
if (it->ret != 0)
itryfree(it->ret);
it->ret = 0;
if ((int32_t)interp->stidx < 0) {
interp->stidx = 0;
return -5;
}
if (ops == 0)
goto next;
it->ret = isolve(it, ops, 0);
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:
free(ops);
norun:
interp->lnidx++;
if (interp->lines[interp->lnidx] != 0)
it->lnidx++;
if (it->lines[it->lnidx] != 0)
goto loop;
return 0;
}
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++);
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;
}
}
fail:
free(interp->lines[interp->lnidx]);
interp->lines[interp->lnidx] = 0;
return fret;
return isolve_(it, ops, count);
}
variable *idoexpr(interpreter *interp, const char *line)
variable *isolve_(instance *it, variable **ops, uint32_t count)
{
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;
// 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 {
indent--;
}
char namebuf[6];
snprintf(namebuf, 6, "arg%d", nargs - j);
if (ops[i]->type == NUMBER)
inew_number(it, namebuf, ops[i]->value.f);
else
inew_string(it, namebuf,
(const char *)ops[i]->value.p);
}
j--;
}
}
if (eol(line[i]))
if (j != 0)
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;
} else {
if (ops[start]->type == CFUNC) {
func_t func = (func_t)ops[start]->value.p;
it->stidx += nargs;
uint32_t sidx = it->stidx;
int ret = 0;
if (!(it->sindent & SKIP))
ret = func(it);
if (ret != 0)
return 0;
}
if (it->stidx > sidx)
ops[start] = (variable *)ipop(it);
else
ops[start] = 0;
ipopm(it, nargs);
} else {
ipush(it, it->lnidx);
ipush(it, CALL_SIG);
it->lnidx = ops[start]->value.p;
}
ops[start + 1] = 0;
for (uint32_t j = start + 2; j < i; j++) {
itryfree(ops[j]);
ops[j] = 0;
}
}
}
if (ops[ooffset] == 0)
return 0;
ooffset++;
// 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;
}
// skip whitespace
skipblank(line, eoe, &offset);
if (eoe(line[offset]))
break;
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;
uint32_t bidx = i + 1;
while (ops[bidx] == 0 && ++bidx < count);
if (bidx == count)
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;
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) // implicit multiply
ops[ooffset] = (void *)1;
return ops[0];
}
ooffset++;
// skip whitespace
skipblank(line, eol, &offset);
}
variable **iparse(instance *it, const char *s)
{
uint32_t ooffset = 0;
size_t offset = 0;
if (ooffset % 2 == 0)
while (isblank(s[offset]))
offset++;
if (s[offset] == '#' || s[offset] == '\0' || s[offset] == '\n')
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;
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 (s[end] == ')')
c--;
}
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;
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);
else
printf("%s", (char *)v->value.p);
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("%.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