mirror of
https://github.com/suchmememanyskill/TegraExplorer.git
synced 2024-11-22 20:06:43 +00:00
implement TScript v2.5
This commit is contained in:
parent
513bd804b1
commit
b0dd71bd4f
15 changed files with 1245 additions and 2 deletions
|
@ -11,6 +11,10 @@
|
||||||
#include <libs/fatfs/ff.h>
|
#include <libs/fatfs/ff.h>
|
||||||
#include "../../utils/utils.h"
|
#include "../../utils/utils.h"
|
||||||
#include "../../keys/nca.h"
|
#include "../../keys/nca.h"
|
||||||
|
#include "../../script/lexer.h"
|
||||||
|
#include "../../script/parser.h"
|
||||||
|
#include "../../script/variables.h"
|
||||||
|
#include <storage/nx_sd.h>
|
||||||
|
|
||||||
MenuEntry_t FileMenuEntries[] = {
|
MenuEntry_t FileMenuEntries[] = {
|
||||||
// Still have to think up the options
|
// Still have to think up the options
|
||||||
|
@ -66,6 +70,27 @@ void DeleteFile(char *path, FSEntry_t entry){
|
||||||
free(thing);
|
free(thing);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RunScript(char *path, FSEntry_t entry){
|
||||||
|
char *thing = CombinePaths(path, entry.name);
|
||||||
|
u32 size;
|
||||||
|
char *script = sd_file_read(thing, &size);
|
||||||
|
free(thing);
|
||||||
|
if (!script)
|
||||||
|
return;
|
||||||
|
|
||||||
|
gfx_clearscreen();
|
||||||
|
scriptCtx_t ctx = createScriptCtx();
|
||||||
|
ctx.script = runLexar(script, size);
|
||||||
|
free(script);
|
||||||
|
|
||||||
|
printError(mainLoop(&ctx));
|
||||||
|
|
||||||
|
freeVariableVector(&ctx.varDict);
|
||||||
|
lexarVectorClear(&ctx.script);
|
||||||
|
gfx_printf("\nend of script");
|
||||||
|
hidWait();
|
||||||
|
}
|
||||||
|
|
||||||
menuPaths FileMenuPaths[] = {
|
menuPaths FileMenuPaths[] = {
|
||||||
CopyClipboard,
|
CopyClipboard,
|
||||||
MoveClipboard,
|
MoveClipboard,
|
||||||
|
@ -73,7 +98,7 @@ menuPaths FileMenuPaths[] = {
|
||||||
DeleteFile,
|
DeleteFile,
|
||||||
UnimplementedException,
|
UnimplementedException,
|
||||||
LaunchPayload,
|
LaunchPayload,
|
||||||
UnimplementedException
|
RunScript
|
||||||
};
|
};
|
||||||
|
|
||||||
void FileMenu(char *path, FSEntry_t entry){
|
void FileMenu(char *path, FSEntry_t entry){
|
||||||
|
|
|
@ -244,6 +244,8 @@ void gfx_putc(char c)
|
||||||
if (gfx_con.y < 16){
|
if (gfx_con.y < 16){
|
||||||
gfx_con.y = YLeftConfig;
|
gfx_con.y = YLeftConfig;
|
||||||
gfx_con.x += 16;
|
gfx_con.x += 16;
|
||||||
|
if (gfx_con.x > 719)
|
||||||
|
gfx_con.x = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (c == '\n')
|
else if (c == '\n')
|
||||||
|
|
404
source/script/args.c
Normal file
404
source/script/args.c
Normal file
|
@ -0,0 +1,404 @@
|
||||||
|
#include "args.h"
|
||||||
|
#include "types.h"
|
||||||
|
#include "functions.h"
|
||||||
|
#include "variables.h"
|
||||||
|
#include <string.h>
|
||||||
|
#include <mem/heap.h>
|
||||||
|
#include "../utils/utils.h"
|
||||||
|
|
||||||
|
char* utils_copyStringSize(const char* in, int size) {
|
||||||
|
if (size > strlen(in) || size < 0)
|
||||||
|
size = strlen(in);
|
||||||
|
|
||||||
|
char* out = calloc(size + 1, 1);
|
||||||
|
//strncpy(out, in, size);
|
||||||
|
if (size)
|
||||||
|
memcpy(out, in, size);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// do not include first openToken!
|
||||||
|
int distanceBetweenTokens(lexarToken_t* tokens, u32 len, int openToken, int closeToken) {
|
||||||
|
int i = 0;
|
||||||
|
int layer = 0;
|
||||||
|
for (; i < len; i++) {
|
||||||
|
if (tokens[i].token == openToken)
|
||||||
|
layer++;
|
||||||
|
else if (tokens[i].token == closeToken) {
|
||||||
|
if (layer == 0)
|
||||||
|
return i;
|
||||||
|
layer--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector_t extractVars(scriptCtx_t* ctx, lexarToken_t* tokens, u32 len) {
|
||||||
|
Vector_t args = newVec(sizeof(Variable_t), 5);
|
||||||
|
int lastLoc = 0;
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
if (tokens[i].token == LSBracket) {
|
||||||
|
int distance = distanceBetweenTokens(&tokens[i + 1], len - i - 1, LSBracket, RSBracket);
|
||||||
|
i += distance + 1;
|
||||||
|
}
|
||||||
|
if (tokens[i].token == Seperator) {
|
||||||
|
Variable_t res = solveEquation(ctx, &tokens[lastLoc], i - lastLoc, 0);
|
||||||
|
lastLoc = i + 1;
|
||||||
|
|
||||||
|
vecAddElement(&args, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i + 1 >= len) {
|
||||||
|
Variable_t res = solveEquation(ctx, &tokens[lastLoc], i + 1 - lastLoc, 0);
|
||||||
|
vecAddElement(&args, res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ErrValue(err) (Variable_t) {.varType = ErrType, .integerType = err}
|
||||||
|
#define IntValue(i) (Variable_t) {.varType = IntType, .integerType = i}
|
||||||
|
#define StrValue(s) (Variable_t) {.varType = StringType, .stringType = s}
|
||||||
|
|
||||||
|
#define ELIFTX(x) else if (tokens[i].token == x)
|
||||||
|
|
||||||
|
Variable_t getVarFromToken(scriptCtx_t* ctx, lexarToken_t* tokens, int* index, u32 maxLen) {
|
||||||
|
Variable_t val = { 0 };
|
||||||
|
int i = *index;
|
||||||
|
|
||||||
|
if (tokens[i].token == Variable) {
|
||||||
|
Variable_t* var = dictVectorFind(&ctx->varDict, tokens[i].text);
|
||||||
|
if (var != NULL) {
|
||||||
|
val = *var;
|
||||||
|
val.free = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
val = ErrValue(ERRNOVAR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ELIFTX(IntLit) {
|
||||||
|
val = IntValue(tokens[i].val);
|
||||||
|
}
|
||||||
|
ELIFTX(StrLit) {
|
||||||
|
val = StrValue(tokens[i].text);
|
||||||
|
val.free = 0;
|
||||||
|
}
|
||||||
|
ELIFTX(ArrayVariable) {
|
||||||
|
Variable_t* var = dictVectorFind(&ctx->varDict, tokens[i].text);
|
||||||
|
i += 2;
|
||||||
|
|
||||||
|
if (var == NULL)
|
||||||
|
return ErrValue(ERRNOVAR);
|
||||||
|
|
||||||
|
int argCount = distanceBetweenTokens(&tokens[i], maxLen - 2, LSBracket, RSBracket);
|
||||||
|
if (argCount < 0)
|
||||||
|
return ErrValue(ERRSYNTAX);
|
||||||
|
|
||||||
|
Variable_t index = solveEquation(ctx, &tokens[i], argCount, 0);
|
||||||
|
i += argCount;
|
||||||
|
|
||||||
|
if (index.varType != IntType)
|
||||||
|
return ErrValue(ERRINVALIDTYPE);
|
||||||
|
|
||||||
|
if (var->vectorType.count <= index.integerType || index.integerType < 0)
|
||||||
|
return ErrValue(ERRSYNTAX);
|
||||||
|
|
||||||
|
switch (var->varType) {
|
||||||
|
case StringArrayType:
|
||||||
|
val = StrValue((vecGetArray(char**, var->vectorType))[index.integerType]);
|
||||||
|
break;
|
||||||
|
case IntArrayType:
|
||||||
|
val = IntValue((vecGetArray(int*, var->vectorType))[index.integerType]);
|
||||||
|
break;
|
||||||
|
case ByteArrayType:
|
||||||
|
val = IntValue((vecGetArray(u8*, var->vectorType))[index.integerType]);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return ErrValue(ERRINVALIDTYPE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ELIFTX(Function) {
|
||||||
|
i += 2;
|
||||||
|
|
||||||
|
int argCount = distanceBetweenTokens(&tokens[i], maxLen - 2, LBracket, RBracket);
|
||||||
|
if (argCount < 0)
|
||||||
|
return ErrValue(ERRSYNTAX);
|
||||||
|
|
||||||
|
val = executeFunction(ctx, tokens[i - 2].text, &tokens[i], argCount);
|
||||||
|
|
||||||
|
//val = IntValue(1);
|
||||||
|
i += argCount;
|
||||||
|
}
|
||||||
|
ELIFTX(LSBracket) {
|
||||||
|
i++;
|
||||||
|
|
||||||
|
int argCount = distanceBetweenTokens(&tokens[i], maxLen - 1, LSBracket, RSBracket);
|
||||||
|
if (argCount <= 0)
|
||||||
|
return ErrValue(ERRSYNTAX);
|
||||||
|
|
||||||
|
// ArrayVars should be a Vector_t containing Variable_t's. Not implemented yet!
|
||||||
|
Vector_t arrayVars = extractVars(ctx, &tokens[i], argCount);
|
||||||
|
Variable_t* variables = vecGetArray(Variable_t*, arrayVars);
|
||||||
|
int type = variables[0].varType;
|
||||||
|
if (!(type == StringType || type == IntType))
|
||||||
|
return ErrValue(ERRINVALIDTYPE);
|
||||||
|
|
||||||
|
val.varType = (type + 2);
|
||||||
|
val.free = 1;
|
||||||
|
val.vectorType = newVec((type == IntType) ? sizeof(int) : sizeof(char*), arrayVars.count);
|
||||||
|
|
||||||
|
for (int i = 0; i < arrayVars.count; i++) {
|
||||||
|
if (variables[i].varType != type)
|
||||||
|
return ErrValue(ERRINVALIDTYPE); // Free-ing issue!!
|
||||||
|
|
||||||
|
if (type == StringType) {
|
||||||
|
char* temp = CpyStr(variables[i].stringType);
|
||||||
|
vecAddElement(&val.vectorType, temp);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
vecAddElement(&val.vectorType, variables[i].integerType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
i += argCount;
|
||||||
|
freeVariableVector(&arrayVars);
|
||||||
|
}
|
||||||
|
ELIFTX(LBracket) {
|
||||||
|
i++;
|
||||||
|
int argCount = distanceBetweenTokens(&tokens[i], maxLen - 1, LBracket, RBracket);
|
||||||
|
if (argCount < 0)
|
||||||
|
return ErrValue(ERRSYNTAX);
|
||||||
|
|
||||||
|
val = solveEquation(ctx, &tokens[i], argCount, 0);
|
||||||
|
i += argCount;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// ERR
|
||||||
|
return ErrValue(ERRSYNTAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
*index = i;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
int matchTypes(Variable_t d1, Variable_t d2, int type) {
|
||||||
|
return (d1.varType == d2.varType && d1.varType == type);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ELIFT(token) else if (localOpToken == token)
|
||||||
|
|
||||||
|
Variable_t solveEquation(scriptCtx_t* ctx, lexarToken_t* tokens, u32 len, u8 shouldFree) {
|
||||||
|
Variable_t res = { 0 };
|
||||||
|
u8 lastToken = 0;
|
||||||
|
u8 invertValue = 0;
|
||||||
|
lexarToken_t* varToken = NULL;
|
||||||
|
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
if (tokens[i].token == Not)
|
||||||
|
invertValue = !invertValue;
|
||||||
|
|
||||||
|
else if (tokens[i].token == ArrayVariableAssignment || tokens[i].token == VariableAssignment) {
|
||||||
|
varToken = &tokens[i];
|
||||||
|
if (tokens[i].token == ArrayVariableAssignment) {
|
||||||
|
int distance = distanceBetweenTokens(&tokens[i] + 2, len, LSBracket, RSBracket);
|
||||||
|
i += distance + 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (tokens[i].token >= Variable && tokens[i].token <= LSBracket) {
|
||||||
|
Variable_t val = getVarFromToken(ctx, tokens, &i, len - i);
|
||||||
|
|
||||||
|
if (val.varType == ErrType)
|
||||||
|
return val;
|
||||||
|
|
||||||
|
if (val.varType == IntType && invertValue) {
|
||||||
|
val.integerType = !val.integerType;
|
||||||
|
}
|
||||||
|
invertValue = 0;
|
||||||
|
|
||||||
|
if (lastToken) {
|
||||||
|
u16 localOpToken = lastToken; // do we need local op token?
|
||||||
|
lastToken = 0;
|
||||||
|
|
||||||
|
if (matchTypes(res, val, IntType)) {
|
||||||
|
if (localOpToken == Plus)
|
||||||
|
res.integerType += val.integerType;
|
||||||
|
ELIFT(Minus)
|
||||||
|
res.integerType -= val.integerType;
|
||||||
|
ELIFT(Multiply)
|
||||||
|
res.integerType *= val.integerType;
|
||||||
|
ELIFT(Division) {
|
||||||
|
if (!val.integerType)
|
||||||
|
res = ErrValue(ERRDIVBYZERO);
|
||||||
|
else
|
||||||
|
res.integerType = res.integerType / val.integerType;
|
||||||
|
}
|
||||||
|
ELIFT(Mod)
|
||||||
|
res.integerType %= val.integerType;
|
||||||
|
ELIFT(Smaller)
|
||||||
|
res.integerType = res.integerType < val.integerType;
|
||||||
|
ELIFT(SmallerEqual)
|
||||||
|
res.integerType = res.integerType <= val.integerType;
|
||||||
|
ELIFT(Bigger)
|
||||||
|
res.integerType = res.integerType > val.integerType;
|
||||||
|
ELIFT(BiggerEqual)
|
||||||
|
res.integerType = res.integerType >= val.integerType;
|
||||||
|
ELIFT(EqualEqual)
|
||||||
|
res.integerType = res.integerType == val.integerType;
|
||||||
|
ELIFT(NotEqual)
|
||||||
|
res.integerType = res.integerType != val.integerType;
|
||||||
|
ELIFT(LogicAND) {
|
||||||
|
res.integerType = res.integerType && val.integerType;
|
||||||
|
if (!res.integerType)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ELIFT(LogicOR) {
|
||||||
|
res.integerType = res.integerType || val.integerType;
|
||||||
|
if (res.integerType)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ELIFT(AND)
|
||||||
|
res.integerType = res.integerType & val.integerType;
|
||||||
|
ELIFT(OR)
|
||||||
|
res.integerType = res.integerType | val.integerType;
|
||||||
|
else
|
||||||
|
return ErrValue(ERRBADOPERATOR);
|
||||||
|
}
|
||||||
|
else if (matchTypes(res, val, StringType)) {
|
||||||
|
if (localOpToken == Plus) {
|
||||||
|
char* buff = calloc(strlen(res.stringType) + strlen(val.stringType) + 1, 1);
|
||||||
|
strcpy(buff, res.stringType);
|
||||||
|
strcat(buff, val.stringType);
|
||||||
|
|
||||||
|
if (res.free) free(res.stringType); // we should replace these with variablefree
|
||||||
|
if (val.free) free(val.stringType);
|
||||||
|
res.stringType = buff;
|
||||||
|
res.free = 1;
|
||||||
|
}
|
||||||
|
ELIFT(EqualEqual) {
|
||||||
|
res.typeUnion = IntType;
|
||||||
|
int compRes = !strcmp(res.stringType, val.stringType);
|
||||||
|
if (res.free) free(res.stringType);
|
||||||
|
if (val.free) free(val.stringType);
|
||||||
|
res.integerType = compRes;
|
||||||
|
res.free = 0;
|
||||||
|
}
|
||||||
|
ELIFT(Minus) {
|
||||||
|
if (!strcmp(res.stringType + strlen(res.stringType) - strlen(val.stringType), val.stringType)) {
|
||||||
|
*(res.stringType + strlen(res.stringType) - strlen(val.stringType)) = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (val.free) free(val.stringType);
|
||||||
|
}
|
||||||
|
ELIFT(Division) {
|
||||||
|
int valLen = strlen(val.stringType);
|
||||||
|
if (!valLen) {
|
||||||
|
res = ErrValue(ERRSYNTAX);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* start = res.stringType;
|
||||||
|
char* find = NULL;
|
||||||
|
//char** arr = malloc(20); // should be dynamic
|
||||||
|
Vector_t arr = newVec(sizeof(char**), 10);
|
||||||
|
char* temp;
|
||||||
|
|
||||||
|
while ((find = (strstr(start, val.stringType))) != NULL) {
|
||||||
|
temp = utils_copyStringSize(start, find - start);
|
||||||
|
vecAddElement(&arr, temp);
|
||||||
|
|
||||||
|
start = find + valLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
temp = utils_copyStringSize(start, res.stringType + strlen(res.stringType) - start);
|
||||||
|
vecAddElement(&arr, temp);
|
||||||
|
if (res.free) free(res.stringType); // do we free here?
|
||||||
|
if (val.free) free(val.stringType);
|
||||||
|
|
||||||
|
res.varType = StringArrayType;
|
||||||
|
res.free = 1;
|
||||||
|
res.vectorType = arr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return ErrValue(ERRBADOPERATOR);
|
||||||
|
}
|
||||||
|
else if ((res.varType == IntArrayType || res.varType == ByteArrayType) && val.varType == IntType) {
|
||||||
|
if (localOpToken == Plus) {
|
||||||
|
Vector_t newV = vecCopy(&res.vectorType);
|
||||||
|
freeVariable(res);
|
||||||
|
res.vectorType = newV;
|
||||||
|
res.free = 1;
|
||||||
|
if (res.varType == IntArrayType)
|
||||||
|
vecAddElement(&res.vectorType, val.integerType);
|
||||||
|
else {
|
||||||
|
u8 in = ((u8)val.integerType & 0xFF);
|
||||||
|
vecAddElement(&res.vectorType, in);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return ErrValue(ERRBADOPERATOR);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
res = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (tokens[i].token >= Plus && tokens[i].token <= OR) {
|
||||||
|
lastToken = tokens[i].token;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (varToken != NULL) {
|
||||||
|
if (varToken->token == VariableAssignment) {
|
||||||
|
dict_t newVar = newDict(CpyStr(varToken->text), res);
|
||||||
|
dictVectorAdd(&ctx->varDict, newVar);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Variable_t* var = dictVectorFind(&ctx->varDict, varToken->text);
|
||||||
|
if (var != NULL) {
|
||||||
|
if (var->varType - 2 == res.varType || (var->varType == ByteArrayType && res.varType == IntType)) {
|
||||||
|
int distance = distanceBetweenTokens(varToken + 2, len, LSBracket, RSBracket);
|
||||||
|
if (distance < 0) {
|
||||||
|
// ERR
|
||||||
|
return ErrValue(ERRSYNTAX);
|
||||||
|
}
|
||||||
|
Variable_t index = solveEquation(ctx, varToken + 2, distance, 0);
|
||||||
|
if (index.varType != IntType) {
|
||||||
|
// ERR
|
||||||
|
}
|
||||||
|
else if (index.integerType < 0 || var->vectorType.count <= index.integerType) {
|
||||||
|
// ERR
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (var->varType == IntArrayType) {
|
||||||
|
int* arr = vecGetArray(int*, var->vectorType);
|
||||||
|
arr[index.integerType] = res.integerType;
|
||||||
|
}
|
||||||
|
else if (var->varType == StringArrayType) {
|
||||||
|
char** arr = vecGetArray(char**, var->vectorType);
|
||||||
|
arr[index.integerType] = CpyStr(res.stringType);
|
||||||
|
}
|
||||||
|
else if (var->varType == ByteArrayType) {
|
||||||
|
u8* arr = vecGetArray(u8*, var->vectorType);
|
||||||
|
arr[index.integerType] = res.integerType & 0xFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// ERR
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//ERR
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (shouldFree) // we should get rid of this ugly free. why not set .free to 0 when assigning it then free in parser.c?
|
||||||
|
freeVariable(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
7
source/script/args.h
Normal file
7
source/script/args.h
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
#pragma once
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
char* utils_copyStringSize(const char* in, int size);
|
||||||
|
Variable_t solveEquation(scriptCtx_t* ctx, lexarToken_t* tokens, u32 len, u8 shouldFree);
|
||||||
|
int distanceBetweenTokens(lexarToken_t* tokens, u32 len, int openToken, int closeToken);
|
||||||
|
Vector_t extractVars(scriptCtx_t* ctx, lexarToken_t* tokens, u32 len);
|
134
source/script/functions.c
Normal file
134
source/script/functions.c
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
#include "types.h"
|
||||||
|
#include "args.h"
|
||||||
|
#include "variables.h"
|
||||||
|
#include <string.h>
|
||||||
|
#include "../gfx/gfx.h"
|
||||||
|
#include <mem/heap.h>
|
||||||
|
#include "lexer.h"
|
||||||
|
|
||||||
|
#define scriptFunction(name) Variable_t name(scriptCtx_t *ctx, Variable_t *vars, u32 varLen)
|
||||||
|
|
||||||
|
scriptFunction(funcIf) {
|
||||||
|
setCurIndentInstruction(ctx, (vars[0].integerType == 0), 0, -1);
|
||||||
|
return NullVar;
|
||||||
|
}
|
||||||
|
|
||||||
|
scriptFunction(funcPrint) {
|
||||||
|
for (u32 i = 0; i < varLen; i++) {
|
||||||
|
if (vars[i].varType == IntType)
|
||||||
|
gfx_printf("%d", vars[i].integerType);
|
||||||
|
else if (vars[i].varType == StringType)
|
||||||
|
gfx_printf("%s", vars[i].stringType);
|
||||||
|
else if (vars[i].varType == IntArrayType) {
|
||||||
|
gfx_printf("[");
|
||||||
|
int* v = vecGetArray(int*, vars[i].vectorType);
|
||||||
|
for (u32 j = 0; j < vars[i].vectorType.count; j++)
|
||||||
|
gfx_printf((j + 1 == vars[i].vectorType.count) ? "%d" : "%d, ", v[j]);
|
||||||
|
gfx_printf("]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NullVar;
|
||||||
|
}
|
||||||
|
|
||||||
|
scriptFunction(funcPrintln) {
|
||||||
|
funcPrint(ctx, vars, varLen);
|
||||||
|
gfx_printf("\n");
|
||||||
|
return NullVar;
|
||||||
|
}
|
||||||
|
|
||||||
|
scriptFunction(funcWhile) {
|
||||||
|
setCurIndentInstruction(ctx, (vars[0].integerType == 0), 0, ctx->startEquation);
|
||||||
|
|
||||||
|
return NullVar;
|
||||||
|
}
|
||||||
|
|
||||||
|
scriptFunction(funcElse) {
|
||||||
|
indentInstructor_t* curInstruction = getCurIndentInstruction(ctx);
|
||||||
|
setCurIndentInstruction(ctx, !curInstruction->skip, 0, -1);
|
||||||
|
return NullVar;
|
||||||
|
}
|
||||||
|
|
||||||
|
scriptFunction(funcLen) {
|
||||||
|
if (vars[0].varType >= IntArrayType && vars[0].varType <= ByteArrayType)
|
||||||
|
return IntVal(vars[0].vectorType.count);
|
||||||
|
else if (vars[0].varType == StringType) {
|
||||||
|
if (vars[0].stringType != NULL)
|
||||||
|
return IntVal(strlen(vars[0].stringType));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ErrVar(ERRINVALIDTYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
scriptFunction(funcMakeByteArray){
|
||||||
|
u8 *buff = malloc(vars[0].vectorType.count);
|
||||||
|
vecDefArray(int*, entries, vars[0].vectorType);
|
||||||
|
for (int i = 0; i < vars[0].vectorType.count; i++)
|
||||||
|
buff[i] = (u8)(entries[i] & 0xFF);
|
||||||
|
|
||||||
|
Vector_t v = vecFromArray(buff, vars[0].vectorType.count, sizeof(u8));
|
||||||
|
return newVar(ByteArrayType, 1, .vectorType = v);
|
||||||
|
}
|
||||||
|
|
||||||
|
u8 singleIntArray[] = { IntArrayType };
|
||||||
|
u8 singleInt[] = { IntType };
|
||||||
|
u8 singleAny[] = { varArgs };
|
||||||
|
|
||||||
|
functionStruct_t scriptFunctions[] = {
|
||||||
|
{"if", funcIf, 1, singleInt},
|
||||||
|
{"print", funcPrint, varArgs, NULL},
|
||||||
|
{"println", funcPrintln, varArgs, NULL},
|
||||||
|
{"while", funcWhile, 1, singleInt},
|
||||||
|
{"else", funcElse, 0, NULL},
|
||||||
|
{"len", funcLen, 1, singleAny},
|
||||||
|
{"byte", funcMakeByteArray, 1, singleIntArray},
|
||||||
|
};
|
||||||
|
|
||||||
|
Variable_t executeFunction(scriptCtx_t* ctx, char* func_name, lexarToken_t *start, u32 len) {
|
||||||
|
Vector_t args = { 0 };
|
||||||
|
|
||||||
|
if (len > 0) {
|
||||||
|
args = extractVars(ctx, start, len);
|
||||||
|
Variable_t* vars = vecGetArray(Variable_t*, args);
|
||||||
|
for (int i = 0; i < args.count; i++) {
|
||||||
|
if (vars[i].varType == ErrType)
|
||||||
|
return vars[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Variable_t* vars = vecGetArray(Variable_t*, args);
|
||||||
|
|
||||||
|
for (u32 i = 0; i < ARRAY_SIZE(scriptFunctions); i++) {
|
||||||
|
if (scriptFunctions[i].argCount == args.count || scriptFunctions[i].argCount == varArgs) {
|
||||||
|
if (!strcmp(scriptFunctions[i].key, func_name)) {
|
||||||
|
if (scriptFunctions[i].argCount != varArgs && scriptFunctions[i].argCount != 0) {
|
||||||
|
u8 argsMatch = 1;
|
||||||
|
for (u32 j = 0; j < args.count; j++) {
|
||||||
|
if (vars[j].varType != scriptFunctions[i].typeArray[j] && scriptFunctions[i].typeArray[j] != varArgs) {
|
||||||
|
argsMatch = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!argsMatch)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Variable_t ret = scriptFunctions[i].value(ctx, vars, args.count);
|
||||||
|
freeVariableVector(&args);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Variable_t* var = dictVectorFind(&ctx->varDict, func_name);
|
||||||
|
if (var != NULL) {
|
||||||
|
if (var->varType == JumpType) {
|
||||||
|
setCurIndentInstruction(ctx, 0, 1, ctx->curPos);
|
||||||
|
ctx->curPos = var->integerType - 1;
|
||||||
|
return NullVar;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ErrVar(ERRNOFUNC);
|
||||||
|
}
|
4
source/script/functions.h
Normal file
4
source/script/functions.h
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
#pragma once
|
||||||
|
#include "variables.h"
|
||||||
|
|
||||||
|
Variable_t executeFunction(scriptCtx_t* ctx, char* func_name, lexarToken_t* start, u32 len);
|
269
source/script/lexer.c
Normal file
269
source/script/lexer.c
Normal file
|
@ -0,0 +1,269 @@
|
||||||
|
#include "lexer.h"
|
||||||
|
#include "types.h"
|
||||||
|
#include "args.h"
|
||||||
|
#include <mem/heap.h>
|
||||||
|
|
||||||
|
static inline int isValidWord(char c) {
|
||||||
|
char r = c | 0x20;
|
||||||
|
return ((r >= 'a' && r <= 'z') || c == '_');
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int isValidNum(char c) {
|
||||||
|
return (c >= '0' && c <= '9');
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int isValidVar(char c) {
|
||||||
|
return (isValidWord(c) || isValidNum(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int isValidHexNum(char c) {
|
||||||
|
char r = c | 0x20;
|
||||||
|
return (isValidNum(r) || (r >= 'a' && r <= 'f'));
|
||||||
|
}
|
||||||
|
|
||||||
|
#define makeLexarToken(token, var) ((lexarToken_t) {token, var})
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
u8 tokenC;
|
||||||
|
u8 tokenN;
|
||||||
|
} lexarTranslation_t;
|
||||||
|
|
||||||
|
lexarTranslation_t lexarTranslations[] = {
|
||||||
|
{'}', RCBracket},
|
||||||
|
{',', Seperator},
|
||||||
|
{'+', Plus},
|
||||||
|
{'-', Minus},
|
||||||
|
{'*', Multiply},
|
||||||
|
{'/', Division},
|
||||||
|
{'%', Mod},
|
||||||
|
{'<', Smaller},
|
||||||
|
{'>', Bigger},
|
||||||
|
{'!', Not},
|
||||||
|
{')', RBracket},
|
||||||
|
{']', RSBracket},
|
||||||
|
{'(', LBracket},
|
||||||
|
{'{', LCBracket},
|
||||||
|
{'=', Equal},
|
||||||
|
{'[', LSBracket},
|
||||||
|
{'\0', 0},
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Should we make vars with next char being '(' a function and vars with an equals (or [x] wait how are we gonna spot that) after it to be an assignmentVar
|
||||||
|
*/
|
||||||
|
|
||||||
|
char lexarDebugGetTokenC(u8 tokenN) {
|
||||||
|
for (int i = 0; lexarTranslations[i].tokenC; i++) {
|
||||||
|
if (lexarTranslations[i].tokenN == tokenN) {
|
||||||
|
return lexarTranslations[i].tokenC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tokenN == EquationSeperator)
|
||||||
|
return ';';
|
||||||
|
|
||||||
|
return '?';
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* !! we need to remake this
|
||||||
|
void lexarVectorClear(lexarVector_t* vec) {
|
||||||
|
for (int i = 0; i < vec->stored; i++) {
|
||||||
|
if (vec->tokens[i].token == Variable || vec->tokens[i].token == StrLit)
|
||||||
|
if (vec->tokens[i].text != NULL)
|
||||||
|
free(vec->tokens[i].text);
|
||||||
|
}
|
||||||
|
free(vec->tokens);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
void lexarVectorClear(Vector_t *v){
|
||||||
|
vecPDefArray(lexarToken_t*, entries, v);
|
||||||
|
|
||||||
|
for (int i = 0; i < v->count; i++){
|
||||||
|
if (entries[i].token != IntLit && entries[i].text != NULL){
|
||||||
|
free(entries[i].text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vecFreePtr(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ELIFC(c) else if (*in == c)
|
||||||
|
|
||||||
|
Vector_t runLexar(const char* in, u32 len) {
|
||||||
|
const char *start = in;
|
||||||
|
Vector_t vec = newVec(sizeof(lexarToken_t), 16);
|
||||||
|
// store last var for re-assignment
|
||||||
|
// var -> func if next obj is '('
|
||||||
|
// var -> assignment if next obj is '='
|
||||||
|
// var -> arrassignment if next obj is '[' and before '=' is ']'
|
||||||
|
// maybe measure len between ( ) and [ ], so this doesn't have to be done during runtime?
|
||||||
|
// We also have to support (()). maybe if '(' set indent level, then if ')' minus indent level, set len. indent level contains {u8 level, u16 token, u16 startoffset}
|
||||||
|
|
||||||
|
while ((in - start) < len) {
|
||||||
|
lexarToken_t* lx = vecGetArray(lexarToken_t*, vec);
|
||||||
|
|
||||||
|
if ((lx[vec.count - 2].token == StrLit || lx[vec.count - 2].token == IntLit || lx[vec.count - 2].token == Variable || lx[vec.count - 2].token == RSBracket || lx[vec.count - 2].token == RBracket)
|
||||||
|
&& (lx[vec.count - 1].token == Variable || lx[vec.count - 1].token == LCBracket || lx[vec.count - 1].token == RCBracket)) {
|
||||||
|
lexarToken_t holder = lx[vec.count - 1];
|
||||||
|
lx[vec.count - 1] = makeLexarToken(EquationSeperator, 0);
|
||||||
|
vecAddElement(&vec, holder);
|
||||||
|
lx = vecGetArray(lexarToken_t*, vec);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isValidWord(*in)) {
|
||||||
|
char* startWord = in;
|
||||||
|
in++;
|
||||||
|
while (isValidVar(*in))
|
||||||
|
in++;
|
||||||
|
|
||||||
|
vecAddElement(&vec, (makeLexarToken(Variable, utils_copyStringSize(startWord, in - startWord))));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (isValidNum(*in) || (*in == '-' && isValidNum(in[1]))) {
|
||||||
|
int parse = 0;
|
||||||
|
u8 negative = (*in == '-');
|
||||||
|
if (negative)
|
||||||
|
in++;
|
||||||
|
|
||||||
|
if (*in == '0' && (in[1] | 0x20) == 'x') {
|
||||||
|
in += 2;
|
||||||
|
while (isValidHexNum(*in)) {
|
||||||
|
parse = parse * 16 + (*in & 0x0F) + (*in >= 'A' ? 9 : 0);
|
||||||
|
in++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else while (isValidNum(*in)) {
|
||||||
|
parse = parse * 10 + *in++ - '0';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (negative)
|
||||||
|
parse *= -1;
|
||||||
|
|
||||||
|
vecAddElement(&vec, makeLexarToken(IntLit, parse));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ELIFC('(') {
|
||||||
|
if (lx[vec.count - 1].token == Variable)
|
||||||
|
lx[vec.count - 1].token = Function;
|
||||||
|
|
||||||
|
vecAddElement(&vec, makeLexarToken(LBracket, 0));
|
||||||
|
}
|
||||||
|
ELIFC('[') {
|
||||||
|
if (lx[vec.count - 1].token == Variable)
|
||||||
|
lx[vec.count - 1].token = ArrayVariable;
|
||||||
|
|
||||||
|
vecAddElement(&vec, makeLexarToken(LSBracket, 0));
|
||||||
|
}
|
||||||
|
ELIFC('=') { // Do we need to keep = if the vars are assignments anyway?
|
||||||
|
if (lx[vec.count - 1].token == Variable)
|
||||||
|
lx[vec.count - 1].token = VariableAssignment;
|
||||||
|
|
||||||
|
else if (lx[vec.count - 1].token == RSBracket) {
|
||||||
|
int back = 1;
|
||||||
|
while (lx[vec.count - back].token != ArrayVariable) {
|
||||||
|
back++;
|
||||||
|
if (vec.count - back < 0)
|
||||||
|
break; // major error
|
||||||
|
}
|
||||||
|
if (lx[vec.count - back].token == ArrayVariable) {
|
||||||
|
lx[vec.count - back].token = ArrayVariableAssignment;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ELIFC('{') {
|
||||||
|
if (lx[vec.count - 1].token == VariableAssignment) {
|
||||||
|
lx[vec.count - 1].token = FunctionAssignment;
|
||||||
|
}
|
||||||
|
vecAddElement(&vec, makeLexarToken(LCBracket, 0));
|
||||||
|
}
|
||||||
|
ELIFC('"') {
|
||||||
|
char* startStr = ++in;
|
||||||
|
int len = 0;
|
||||||
|
while (*in != '"') {
|
||||||
|
in++;
|
||||||
|
}
|
||||||
|
len = in - startStr;
|
||||||
|
|
||||||
|
char* storage = malloc(len + 1);
|
||||||
|
|
||||||
|
int pos = 0;
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
if (startStr[i] == '\\') {
|
||||||
|
if (startStr[i + 1] == 'n') {
|
||||||
|
storage[pos++] = '\n';
|
||||||
|
i++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startStr[i + 1] == 'r') {
|
||||||
|
storage[pos++] = '\r';
|
||||||
|
i++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
storage[pos++] = startStr[i];
|
||||||
|
}
|
||||||
|
storage[pos] = '\0';
|
||||||
|
|
||||||
|
vecAddElement(&vec, makeLexarToken(StrLit, storage));
|
||||||
|
}
|
||||||
|
ELIFC('#') {
|
||||||
|
while (*in != '\n')
|
||||||
|
in++;
|
||||||
|
}
|
||||||
|
ELIFC('&') {
|
||||||
|
if (in[1] == '&') {
|
||||||
|
vecAddElement(&vec, makeLexarToken(LogicAND, 0));
|
||||||
|
in++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
vecAddElement(&vec, makeLexarToken(AND, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ELIFC('|') {
|
||||||
|
if (in[1] == '|') {
|
||||||
|
vecAddElement(&vec, makeLexarToken(LogicOR, 0));
|
||||||
|
in++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
vecAddElement(&vec, makeLexarToken(OR, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int val = 0;
|
||||||
|
|
||||||
|
for (int i = 0; lexarTranslations[i].tokenC; i++) {
|
||||||
|
if (lexarTranslations[i].tokenC == *in) {
|
||||||
|
val = lexarTranslations[i].tokenN;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
in++;
|
||||||
|
|
||||||
|
if (*in == '=' && val >= Smaller && val <= Not) {
|
||||||
|
val++;
|
||||||
|
in++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (val != Invalid)
|
||||||
|
vecAddElement(&vec, makeLexarToken(val, 0));
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
in++;
|
||||||
|
}
|
||||||
|
|
||||||
|
lexarToken_t* lx = vecGetArray(lexarToken_t*, vec);
|
||||||
|
if ((lx[vec.count - 2].token == StrLit || lx[vec.count - 2].token == IntLit || lx[vec.count - 2].token == Variable || lx[vec.count - 2].token == RSBracket || lx[vec.count - 2].token == RBracket)
|
||||||
|
&& (lx[vec.count - 1].token == Variable || lx[vec.count - 1].token == LCBracket || lx[vec.count - 1].token == RCBracket)) {
|
||||||
|
lexarToken_t holder = lx[vec.count - 1];
|
||||||
|
lx[vec.count - 1] = makeLexarToken(EquationSeperator, 0);
|
||||||
|
vecAddElement(&vec, holder);
|
||||||
|
}
|
||||||
|
|
||||||
|
vecAddElement(&vec, makeLexarToken(EquationSeperator, 0));
|
||||||
|
return vec;
|
||||||
|
}
|
6
source/script/lexer.h
Normal file
6
source/script/lexer.h
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
#pragma once
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
Vector_t runLexar(const char* in, u32 len);
|
||||||
|
char lexarDebugGetTokenC(u8 tokenN);
|
||||||
|
void lexarVectorClear(Vector_t *v);
|
109
source/script/parser.c
Normal file
109
source/script/parser.c
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
#include "args.h"
|
||||||
|
#include "types.h"
|
||||||
|
#include "variables.h"
|
||||||
|
#include "lexer.h"
|
||||||
|
#include "../gfx/gfx.h"
|
||||||
|
#include "../utils/utils.h"
|
||||||
|
#include <mem/heap.h>
|
||||||
|
|
||||||
|
#define scriptResultCreate(resCode, nearToken) (scriptResult_t) {resCode, nearToken, 1}
|
||||||
|
#define scriptResultCreateLen(resCode, nearToken, len) (scriptResult_t) {resCode, nearToken, len}
|
||||||
|
|
||||||
|
scriptResult_t runFunction(scriptCtx_t* ctx, u32 len) {
|
||||||
|
lexarToken_t* tokens = vecGetArray(lexarToken_t*, ctx->script);
|
||||||
|
Variable_t res = solveEquation(ctx, &tokens[ctx->startEquation], len, 1);
|
||||||
|
|
||||||
|
if (res.varType == ErrType) {
|
||||||
|
return scriptResultCreateLen(res.integerType, &tokens[ctx->startEquation], len);
|
||||||
|
}
|
||||||
|
|
||||||
|
return scriptResultCreate(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define RUNFUNCWITHPANIC(ctx, len) scriptResult_t res = runFunction(ctx, len); if (res.resCode != 0) return res
|
||||||
|
|
||||||
|
static inline int checkIfVar(u8 token) {
|
||||||
|
return (token == StrLit || token == IntLit || token == Variable || token == RSBracket || token == ArrayVariable);
|
||||||
|
}
|
||||||
|
|
||||||
|
scriptResult_t mainLoop(scriptCtx_t* ctx) {
|
||||||
|
ctx->startEquation = 0;
|
||||||
|
lexarToken_t* lexArr = vecGetArray(lexarToken_t*, ctx->script);
|
||||||
|
for (ctx->curPos = 0; ctx->curPos < ctx->script.count; ctx->curPos++) {
|
||||||
|
u32 i = ctx->curPos;
|
||||||
|
lexarToken_t curToken = lexArr[i];
|
||||||
|
|
||||||
|
if (curToken.token == EquationSeperator) {
|
||||||
|
RUNFUNCWITHPANIC(ctx, ctx->curPos - ctx->startEquation);
|
||||||
|
ctx->startEquation = ctx->curPos + 1;
|
||||||
|
}
|
||||||
|
else if (curToken.token == FunctionAssignment) {
|
||||||
|
setCurIndentInstruction(ctx, 1, 0, -1);
|
||||||
|
dict_t x = newDict(CpyStr(curToken.text), newVar(JumpType, 0, .integerType = ctx->curPos + 1));
|
||||||
|
vecAddElement(&ctx->varDict, x);
|
||||||
|
}
|
||||||
|
else if (curToken.token == LCBracket) {
|
||||||
|
indentInstructor_t* ins = getCurIndentInstruction(ctx);
|
||||||
|
if (ins->active) {
|
||||||
|
if (ins->skip) {
|
||||||
|
int distance = distanceBetweenTokens(&lexArr[i + 1], ctx->script.count - i - 1, LCBracket, RCBracket);
|
||||||
|
if (distance < 0)
|
||||||
|
return scriptResultCreate(ERRSYNTAX, &lexArr[i]);
|
||||||
|
ctx->curPos += distance + 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ctx->indentIndex++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return scriptResultCreate(ERRINACTIVEINDENT, &lexArr[i]);
|
||||||
|
|
||||||
|
ctx->startEquation = ctx->curPos + 1;
|
||||||
|
}
|
||||||
|
else if (curToken.token == RCBracket) {
|
||||||
|
ctx->indentIndex--;
|
||||||
|
indentInstructor_t* ins = getCurIndentInstruction(ctx);
|
||||||
|
if (ins->active && ins->jump) {
|
||||||
|
ctx->curPos = ins->jumpLoc - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ins->active = 0;
|
||||||
|
ctx->startEquation = ctx->curPos + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return scriptResultCreate(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void printToken(lexarToken_t* token) {
|
||||||
|
switch (token->token) {
|
||||||
|
case Variable:
|
||||||
|
case VariableAssignment:
|
||||||
|
case Function:
|
||||||
|
case FunctionAssignment:
|
||||||
|
case ArrayVariable:
|
||||||
|
case ArrayVariableAssignment:
|
||||||
|
gfx_printf("%s", token->text);
|
||||||
|
break;
|
||||||
|
case StrLit:
|
||||||
|
//printf("%d: '%s'\n", vec.tokens[i].token, vec.tokens[i].text);
|
||||||
|
gfx_printf("\"%s\"", token->text);
|
||||||
|
break;
|
||||||
|
case IntLit:
|
||||||
|
//printf("%d: %d\n", vec.tokens[i].token, vec.tokens[i].val);
|
||||||
|
gfx_printf("%d", token->val);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
//printf("%d: %c\n", vec.tokens[i].token, lexarDebugGetTokenC(vec.tokens[i].token));
|
||||||
|
gfx_printf("%c", lexarDebugGetTokenC(token->token));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void printError(scriptResult_t res) {
|
||||||
|
if (res.resCode) {
|
||||||
|
gfx_printf("Error %d found!\nNear: ", res.resCode);
|
||||||
|
for (int i = 0; i < res.len; i++) {
|
||||||
|
printToken(&res.nearToken[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
6
source/script/parser.h
Normal file
6
source/script/parser.h
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
scriptResult_t mainLoop(scriptCtx_t* ctx);
|
||||||
|
void printError(scriptResult_t res);
|
140
source/script/types.h
Normal file
140
source/script/types.h
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <utils/types.h>
|
||||||
|
#include "../utils/vector.h"
|
||||||
|
|
||||||
|
enum Tokens {
|
||||||
|
Invalid = 0,
|
||||||
|
Variable = 1,
|
||||||
|
ArrayVariable,
|
||||||
|
Function,
|
||||||
|
LBracket,
|
||||||
|
StrLit,
|
||||||
|
IntLit,
|
||||||
|
LSBracket,
|
||||||
|
VariableAssignment,
|
||||||
|
ArrayVariableAssignment,
|
||||||
|
FunctionAssignment,
|
||||||
|
RBracket,
|
||||||
|
RCBracket,
|
||||||
|
LCBracket,
|
||||||
|
Seperator,
|
||||||
|
Plus,
|
||||||
|
Minus,
|
||||||
|
Multiply,
|
||||||
|
Division,
|
||||||
|
Mod,
|
||||||
|
Smaller,
|
||||||
|
SmallerEqual,
|
||||||
|
Bigger,
|
||||||
|
BiggerEqual,
|
||||||
|
Equal,
|
||||||
|
EqualEqual,
|
||||||
|
Not,
|
||||||
|
NotEqual,
|
||||||
|
LogicAND,
|
||||||
|
LogicOR,
|
||||||
|
RSBracket,
|
||||||
|
AND,
|
||||||
|
OR,
|
||||||
|
EquationSeperator,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
u8 token;
|
||||||
|
union {
|
||||||
|
char* text;
|
||||||
|
int val;
|
||||||
|
};
|
||||||
|
} lexarToken_t;
|
||||||
|
|
||||||
|
enum Errors {
|
||||||
|
ERRBADOPERATOR = 1,
|
||||||
|
ERRDOUBLENOT,
|
||||||
|
ERRSYNTAX,
|
||||||
|
ERRINVALIDTYPE,
|
||||||
|
ERRNOVAR,
|
||||||
|
ERRNOFUNC,
|
||||||
|
ERRINACTIVEINDENT,
|
||||||
|
ERRDIVBYZERO
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Variables {
|
||||||
|
IntType = 0,
|
||||||
|
StringType,
|
||||||
|
IntArrayType,
|
||||||
|
StringArrayType,
|
||||||
|
ByteArrayType,
|
||||||
|
JumpType,
|
||||||
|
DictType,
|
||||||
|
NullType,
|
||||||
|
ErrType,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct { // this is to keep track of how many {} we passed. Keep an internal var with the "indentation level", +1 for {, -1 for }. have an array with the following def on what to do (on func: enter, set indentation & jump back, on while, jump to while, use while as if, on if simply set true or false)
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
u8 active : 1;
|
||||||
|
u8 skip : 1;
|
||||||
|
u8 jump : 1;
|
||||||
|
u8 function : 1;
|
||||||
|
};
|
||||||
|
u8 container;
|
||||||
|
};
|
||||||
|
int jumpLoc;
|
||||||
|
} indentInstructor_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
u8 varType : 7;
|
||||||
|
u8 free : 1;
|
||||||
|
};
|
||||||
|
u8 typeUnion;
|
||||||
|
};
|
||||||
|
union {
|
||||||
|
int integerType;
|
||||||
|
char* stringType;
|
||||||
|
Vector_t vectorType;
|
||||||
|
};
|
||||||
|
} Variable_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char* key;
|
||||||
|
Variable_t value;
|
||||||
|
} dict_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Vector_t indentInstructors; // Type indentInstructor_t
|
||||||
|
Vector_t varDict; // Type dict_t
|
||||||
|
Vector_t script; // Type lexarToken_t
|
||||||
|
u32 startEquation;
|
||||||
|
u32 curPos;
|
||||||
|
u8 indentIndex;
|
||||||
|
} scriptCtx_t;
|
||||||
|
|
||||||
|
typedef Variable_t(*func_int_ptr)(scriptCtx_t* ctx, Variable_t *vars, u32 len);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char* key;
|
||||||
|
func_int_ptr value;
|
||||||
|
u8 argCount;
|
||||||
|
u8* typeArray;
|
||||||
|
} functionStruct_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int resCode;
|
||||||
|
lexarToken_t* nearToken;
|
||||||
|
u32 len;
|
||||||
|
} scriptResult_t;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define newDict(strName, var) (dict_t) {strName, var}
|
||||||
|
#define newVar(var, frii, value) (Variable_t) {.varType = var, .free = frii, value}
|
||||||
|
|
||||||
|
#define varArgs 255
|
||||||
|
|
||||||
|
#define NullVar newVar(NullType, 0, 0)
|
||||||
|
#define ErrVar(err) newVar(ErrType, 0, err)
|
||||||
|
#define IntVal(val) newVar(IntType, 0, val)
|
105
source/script/variables.c
Normal file
105
source/script/variables.c
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
#include "variables.h"
|
||||||
|
#include "types.h"
|
||||||
|
#include <string.h>
|
||||||
|
#include <mem/heap.h>
|
||||||
|
|
||||||
|
void freeVariable(Variable_t dv) {
|
||||||
|
if (!dv.free)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (dv.varType) {
|
||||||
|
case StringType:
|
||||||
|
FREE(dv.stringType);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case StringArrayType:;
|
||||||
|
char** strArray = vecGetArray(char**, dv.vectorType);
|
||||||
|
for (u32 i = 0; i < dv.vectorType.count; i++){
|
||||||
|
FREE(strArray[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
case IntArrayType:
|
||||||
|
case ByteArrayType:
|
||||||
|
vecFree(dv.vectorType);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void freeVariableVector(Vector_t *v) {
|
||||||
|
Variable_t* vars = vecGetArrayPtr(v, Variable_t*);
|
||||||
|
for (int i = 0; i < v->count; i++) {
|
||||||
|
freeVariable(vars[i]);
|
||||||
|
}
|
||||||
|
vecFreePtr(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
void freeDictVector(Vector_t *v) {
|
||||||
|
dict_t* dic = vecGetArrayPtr(v, dict_t*);
|
||||||
|
for (int i = 0; i < v->count; i++) {
|
||||||
|
FREE(dic[i].key);
|
||||||
|
freeVariable(dic[i].value);
|
||||||
|
}
|
||||||
|
vecFreePtr(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
Variable_t* dictVectorFind(Vector_t* v, const char* key) {
|
||||||
|
dict_t* dic = vecGetArrayPtr(v, dict_t*);
|
||||||
|
for (int i = 0; i < v->count; i++) {
|
||||||
|
if (!strcmp(dic[i].key, key))
|
||||||
|
return &dic[i].value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dictVectorAdd(Vector_t* v, dict_t add) {
|
||||||
|
if (add.key == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Variable_t* var = dictVectorFind(v, add.key);
|
||||||
|
|
||||||
|
if (var != NULL) {
|
||||||
|
if ((var->varType >= StringType && var->varType <= ByteArrayType && var->varType == add.value.varType) && (add.value.stringType == var->stringType || add.value.vectorType.data == var->vectorType.data))
|
||||||
|
return;
|
||||||
|
|
||||||
|
freeVariable(*var);
|
||||||
|
*var = add.value;
|
||||||
|
free(add.key);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
vecAddElement(v, add);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
scriptCtx_t createScriptCtx() {
|
||||||
|
scriptCtx_t s = {
|
||||||
|
.indentInstructors = newVec(sizeof(indentInstructor_t), 64),
|
||||||
|
.varDict = newVec(sizeof(dict_t), 8),
|
||||||
|
.startEquation = 0,
|
||||||
|
.curPos = 0
|
||||||
|
};
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We should rewrite this to actually use the vector!
|
||||||
|
u8 setIndentInstruction(scriptCtx_t* ctx, u8 level, u8 skip, u8 func, int jumpLoc) {
|
||||||
|
if (level >= 64)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
indentInstructor_t* instructors = vecGetArray(indentInstructor_t*, ctx->indentInstructors);
|
||||||
|
indentInstructor_t* instructor = &instructors[level];
|
||||||
|
|
||||||
|
instructor->skip = skip;
|
||||||
|
instructor->active = 1;
|
||||||
|
instructor->function = func;
|
||||||
|
instructor->jump = (jumpLoc >= 0) ? 1 : 0;
|
||||||
|
instructor->jumpLoc = jumpLoc;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
indentInstructor_t* getCurIndentInstruction(scriptCtx_t* ctx) {
|
||||||
|
indentInstructor_t* instructors = vecGetArray(indentInstructor_t*, ctx->indentInstructors);
|
||||||
|
return &instructors[ctx->indentIndex];
|
||||||
|
}
|
16
source/script/variables.h
Normal file
16
source/script/variables.h
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
#pragma once
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
void dictVectorAdd(Vector_t* v, dict_t add);
|
||||||
|
Variable_t* dictVectorFind(Vector_t* v, const char* key);
|
||||||
|
void freeDictVector(Vector_t* v);
|
||||||
|
void freeVariableVector(Vector_t* v);
|
||||||
|
void freeVariable(Variable_t dv);
|
||||||
|
scriptCtx_t createScriptCtx();
|
||||||
|
|
||||||
|
u8 setIndentInstruction(scriptCtx_t* ctx, u8 level, u8 skip, u8 func, int jumpLoc);
|
||||||
|
indentInstructor_t* getCurIndentInstruction(scriptCtx_t* ctx);
|
||||||
|
|
||||||
|
static inline u8 setCurIndentInstruction(scriptCtx_t* ctx, u8 skip, u8 func, int jumpLoc) {
|
||||||
|
return setIndentInstruction(ctx, ctx->indentIndex, skip, func, jumpLoc);
|
||||||
|
}
|
|
@ -45,4 +45,11 @@ bool vecAdd(Vector_t* v, void* elem, u32 sz)
|
||||||
memcpy((char*)v->data + usedbytes, elem, sz);
|
memcpy((char*)v->data + usedbytes, elem, sz);
|
||||||
v->count++;
|
v->count++;
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector_t vecCopy(Vector_t* orig) {
|
||||||
|
Vector_t dst = newVec(orig->elemSz, orig->count);
|
||||||
|
memcpy(dst.data, orig->data, orig->count * orig->elemSz);
|
||||||
|
dst.count = orig->count;
|
||||||
|
return dst;
|
||||||
}
|
}
|
|
@ -9,12 +9,21 @@ typedef struct {
|
||||||
// u32 typeTag;
|
// u32 typeTag;
|
||||||
} Vector_t;
|
} Vector_t;
|
||||||
|
|
||||||
|
#define FREE(x) free(x); x = NULL;
|
||||||
|
|
||||||
#define vecAddElem(v, elem) vecAdd(v, &elem, sizeof(elem))
|
#define vecAddElem(v, elem) vecAdd(v, &elem, sizeof(elem))
|
||||||
|
#define vecAddElement(v, elem) vecAdd(v, &elem, sizeof(elem))
|
||||||
#define vecDefArray(type, varName, vec) type varName = (type)((vec).data)
|
#define vecDefArray(type, varName, vec) type varName = (type)((vec).data)
|
||||||
#define vecGetArray(type, vec) (type)((vec).data)
|
#define vecGetArray(type, vec) (type)((vec).data)
|
||||||
#define vecPDefArray(type, varName, vec) type varName = (type)((vec)->data)
|
#define vecPDefArray(type, varName, vec) type varName = (type)((vec)->data)
|
||||||
#define vecPGetArray(type, vec) (type)((vec)->data)
|
#define vecPGetArray(type, vec) (type)((vec)->data)
|
||||||
|
#define vecFreePtr(vec) FREE(vec->data)
|
||||||
|
#define vecFree(vec) FREE(vec.data)
|
||||||
|
#define vecGetCapacity(vec) (vec.capacity / vec.elemSz)
|
||||||
|
|
||||||
|
#define vecGetArrayPtr(vec, type) (type)((vec)->data)
|
||||||
|
|
||||||
Vector_t newVec(u32 typesz, u32 preallocate);
|
Vector_t newVec(u32 typesz, u32 preallocate);
|
||||||
Vector_t vecFromArray(void* array, u32 count, u32 typesz);
|
Vector_t vecFromArray(void* array, u32 count, u32 typesz);
|
||||||
bool vecAdd(Vector_t* v, void* elem, u32 sz);
|
bool vecAdd(Vector_t* v, void* elem, u32 sz);
|
||||||
|
Vector_t vecCopy(Vector_t* orig);
|
Loading…
Reference in a new issue