initial commit
commit
548804f4b4
@ -0,0 +1,2 @@
|
||||
shell
|
||||
*.o
|
@ -0,0 +1,7 @@
|
||||
CC = gcc -m32
|
||||
|
||||
CFLAGS = -Wall -Wextra -I. -ggdb -fno-builtin
|
||||
|
||||
all:
|
||||
$(CC) $(CFLAGS) -c parser.c
|
||||
$(CC) $(CFLAGS) shell.c parser.o -o shell
|
@ -0,0 +1,6 @@
|
||||
# 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(), expecting a filesystem. This interpreter aims to be as independent as possible: parsing script from strings at a time, having minimal built-in functions (so the user can define their own prints and such), and only requiring a few library functions.
|
||||
|
||||
To use this program with your own device, only two functions are truly needed: malloc, and strcmp.
|
||||
|
||||
This project is still in heavy development, so don't expect much. Right now only function calls are supported, without variable name expansion. To include it in your own project, just link in parser.o and use the header files.
|
@ -0,0 +1,205 @@
|
||||
#include <parser.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static const char *interpreter_operators = "=(";
|
||||
|
||||
uint8_t isalpha(char c)
|
||||
{
|
||||
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
|
||||
}
|
||||
|
||||
uint8_t isnum(char c)
|
||||
{
|
||||
return (c >= '0' && c <= '9');
|
||||
}
|
||||
|
||||
uint8_t isname(char c)
|
||||
{
|
||||
return isalpha(c) || isnum(c);
|
||||
}
|
||||
|
||||
uint8_t isspace(char c)
|
||||
{
|
||||
return (c == ' ' || c == '\t' || c == '\n');
|
||||
}
|
||||
|
||||
uint8_t isoper(char c)
|
||||
{
|
||||
for (uint8_t i = 0; i < sizeof(interpreter_operators); i++) {
|
||||
if (c == interpreter_operators[i])
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void interpreter_init(interpreter *interp)
|
||||
{
|
||||
interp->status = READY;
|
||||
interp->vcount = 0;
|
||||
interp->vars = (variable *)calloc(32, sizeof(variable));
|
||||
interp->names = (char **)calloc(32, sizeof(char *));
|
||||
interp->stack = (stack_t *)calloc(64, sizeof(stack_t));
|
||||
}
|
||||
|
||||
void interpreter_define_value(interpreter *interp, const char *name, int32_t value)
|
||||
{
|
||||
interp->names[interp->vcount] = (char *)name;
|
||||
interp->vars[interp->vcount].nameidx = interp->vcount;
|
||||
interp->vars[interp->vcount].type = VALUE;
|
||||
interp->vars[interp->vcount].value = (uint32_t)value;
|
||||
interp->vcount++;
|
||||
}
|
||||
|
||||
void interpreter_define_cfunc(interpreter *interp, const char *name, func_t addr)
|
||||
{
|
||||
interp->names[interp->vcount] = (char *)name;
|
||||
interp->vars[interp->vcount].nameidx = interp->vcount;
|
||||
interp->vars[interp->vcount].type = CFUNCTION;
|
||||
interp->vars[interp->vcount].value = (uint32_t)addr;
|
||||
interp->vcount++;
|
||||
}
|
||||
|
||||
int32_t interpreter_get_value(interpreter *interp, const char *name)
|
||||
{
|
||||
for (uint16_t i = 0; i < interp->vcount; i++) {
|
||||
if (!strcmp(interp->names[i], name))
|
||||
return (int32_t)interp->vars[i].value;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* doline section
|
||||
*/
|
||||
|
||||
bool namencmp(const char *name, const char *s)
|
||||
{
|
||||
uint16_t i;
|
||||
for (i = 0; name[i] == s[i] && s[i] != '\0'; i++);
|
||||
return (name[i] == '\0');
|
||||
}
|
||||
|
||||
uint16_t spacecount(const char *s)
|
||||
{
|
||||
uint16_t i;
|
||||
for (i = 0; isspace(s[i]); i++);
|
||||
return i;
|
||||
}
|
||||
|
||||
char *copystr(const char *s)
|
||||
{
|
||||
uint16_t len = 0;
|
||||
while (s[len++] != '\n');
|
||||
char *buf = (char *)malloc(len);
|
||||
for (uint16_t i = 0; i < len; i++)
|
||||
buf[i] = s[i];
|
||||
return buf;
|
||||
}
|
||||
|
||||
char *copysubstr(const char *s, int end)
|
||||
{
|
||||
char *buf = (char *)malloc(end);
|
||||
for (uint16_t i = 0; i < end; i++)
|
||||
buf[i] = s[i];
|
||||
return buf;
|
||||
}
|
||||
|
||||
int interpreter_doline(interpreter *interp, const char *line)
|
||||
{
|
||||
variable *bits[16];
|
||||
uint16_t offset = 0, boffset = 0;
|
||||
|
||||
// check for var/func set or usage
|
||||
getvar:
|
||||
for (uint16_t i = 0; i < interp->vcount; i++) {
|
||||
if (namencmp(interp->names[i], line)) {
|
||||
bits[boffset++] = &interp->vars[i];
|
||||
// get past name
|
||||
for (uint16_t j = 0; interp->names[i][j] != '\0'; j++, offset++);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// defining new variable
|
||||
if (boffset == 0) {
|
||||
uint16_t end;
|
||||
for (end = 0; isname(line[end]); end++);
|
||||
interpreter_define_value(interp, copysubstr(line, end), 0);
|
||||
goto getvar; // try again
|
||||
}
|
||||
|
||||
// skip whitespace
|
||||
offset += spacecount(line + offset);
|
||||
|
||||
if (boffset == 0 && line[offset] != '=')
|
||||
return -1; // variable not found
|
||||
|
||||
// find operator
|
||||
if (line[offset] == '\0') {
|
||||
// print value
|
||||
return -99;
|
||||
} else if (line[offset] == '=') {
|
||||
return -23;
|
||||
// assignment/expression
|
||||
//offset++;
|
||||
//offset += spacecount(line + offset);
|
||||
//if (boffset > 0)
|
||||
// bits[boffset]->value = (uint32_t)copystr(line + offset);
|
||||
} else if (line[offset] == '(') {
|
||||
// function call
|
||||
offset++;
|
||||
if (bits[0]->type != FUNCTION && bits[0]->type != CFUNCTION)
|
||||
return -2;
|
||||
offset += spacecount(line + offset);
|
||||
|
||||
// collect arg offsets
|
||||
uint16_t offsets[8];
|
||||
uint8_t ooffset = 0;
|
||||
while (line[offset] != ')' && line[offset] != '\0') {
|
||||
offsets[ooffset] = offset;
|
||||
offset += spacecount(line + offset);
|
||||
|
||||
uint8_t isvn = 1;
|
||||
do {
|
||||
if (line[offset] == ' ' || line[offset] == '\t') {
|
||||
offset += spacecount(line + offset);
|
||||
isvn = 0;
|
||||
}
|
||||
|
||||
if (line[offset] == ',') {
|
||||
offset++;
|
||||
ooffset++;
|
||||
break;
|
||||
} else if (line[offset] == ')') {
|
||||
ooffset++;
|
||||
break;
|
||||
} else if (isvn == 0) {
|
||||
return -3;
|
||||
}
|
||||
} while (++offset);
|
||||
}
|
||||
|
||||
// populate stack
|
||||
for (uint8_t i = 0; i < ooffset; i++) {
|
||||
uint16_t j;
|
||||
for (j = offsets[i]; line[j] != ' ' && line[j] != '\t' &&
|
||||
line[j] != ',' && line[j] != ')'; j++);
|
||||
j -= offsets[i];
|
||||
interp->stack[i] = (char *)malloc(j);
|
||||
for (uint16_t k = 0; k < j; k++)
|
||||
((char *)interp->stack[i])[k] = line[offsets[i] + k];
|
||||
}
|
||||
|
||||
((func_t)bits[0]->value)(interp->stack);
|
||||
} else {
|
||||
return -2; // invalid operation
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -0,0 +1,31 @@
|
||||
#ifndef PARSER_H_
|
||||
#define PARSER_H_
|
||||
|
||||
#include <variable.h>
|
||||
|
||||
typedef void *stack_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t status;
|
||||
uint16_t vcount;
|
||||
variable *vars;
|
||||
char **names;
|
||||
stack_t *stack;
|
||||
} interpreter;
|
||||
|
||||
enum status {
|
||||
READY = 0
|
||||
};
|
||||
|
||||
typedef void (*func_t)(stack_t *);
|
||||
|
||||
void interpreter_init(interpreter *);
|
||||
|
||||
void interpreter_define_value(interpreter *, const char *, int32_t);
|
||||
void interpreter_define_cfunc(interpreter *, const char *, func_t);
|
||||
|
||||
int32_t interpreter_get_value(interpreter *, const char *);
|
||||
|
||||
int interpreter_doline(interpreter *, const char *);
|
||||
|
||||
#endif // PARSER_H_
|
@ -0,0 +1,23 @@
|
||||
#include <parser.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
void test(stack_t *stack)
|
||||
{
|
||||
printf("%s\n", stack[0]);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
interpreter interp;
|
||||
|
||||
interpreter_init(&interp);
|
||||
interpreter_define_value(&interp, "answer", 42);
|
||||
interpreter_define_cfunc(&interp, "test", test);
|
||||
|
||||
if (argc == 2) {
|
||||
printf("%d\n", interpreter_doline(&interp, argv[1]));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
#ifndef TOKEN_H_
|
||||
#define TOKEN_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct {
|
||||
uint16_t nameidx;
|
||||
uint8_t type;
|
||||
uint8_t info;
|
||||
uint32_t value;
|
||||
} variable;
|
||||
|
||||
#define INFO_ARGS(x) ((x) & 0x07)
|
||||
#define INFO_RET (1 << 3)
|
||||
|
||||
enum vartype {
|
||||
VALUE = 0,
|
||||
VARIABLE,
|
||||
OPERATOR,
|
||||
FUNCTION,
|
||||
CFUNCTION
|
||||
};
|
||||
|
||||
#endif // TOKEN_H_
|
Loading…
Reference in New Issue