start of tsV2
This commit is contained in:
@@ -1,307 +1,263 @@
|
||||
#include "args.h"
|
||||
#include "parser.h"
|
||||
#include "types.h"
|
||||
#include "list.h"
|
||||
#include "functions.h"
|
||||
#include "scriptCtx.h"
|
||||
#include "lexer.h"
|
||||
#include <string.h>
|
||||
#include "../../mem/heap.h"
|
||||
#include "../gfx/gfxutils.h"
|
||||
#include "../emmc/emmc.h"
|
||||
#include "../../utils/types.h"
|
||||
#include "../../libs/fatfs/ff.h"
|
||||
#include "../../utils/sprintf.h"
|
||||
#include "../../utils/btn.h"
|
||||
#include "../../gfx/gfx.h"
|
||||
#include "../../utils/util.h"
|
||||
#include "../../storage/emummc.h"
|
||||
#include "parser.h"
|
||||
#include "../common/common.h"
|
||||
#include "../fs/fsactions.h"
|
||||
#include "functions.h"
|
||||
#include "variables.h"
|
||||
#include "../fs/fsreader.h"
|
||||
#include "../utils/utils.h"
|
||||
#include "../../storage/nx_sd.h"
|
||||
#include "../../gfx/gfx.h"
|
||||
#include "../../hid/hid.h"
|
||||
#include "../gfx/gfxutils.h"
|
||||
|
||||
int countchars(const char* in, char target) {
|
||||
u32 len = strlen(in);
|
||||
u32 count = 0;
|
||||
|
||||
for (u32 i = 0; i < len; i++) {
|
||||
if (in[i] == '"'){
|
||||
while (in[++i] != '"'){
|
||||
if (i >= len)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (in[i] == target)
|
||||
count++;
|
||||
}
|
||||
//#define DPRINTF(str, ...) printf(str, __VA_ARGS__)
|
||||
#define DPRINTF
|
||||
|
||||
return count;
|
||||
#define findNextCharsCtx(ctx, targets) findNextChars(&(ctx->curPos), targets)
|
||||
|
||||
int checkIfVar(u16 token) {
|
||||
return (token == StrLit || token == IntLit || token == Variable || token == RSBracket);
|
||||
}
|
||||
|
||||
char **argv = NULL;
|
||||
u32 argc;
|
||||
u32 splitargs(const char* in) {
|
||||
// arg like '5, "6", @arg7'
|
||||
u32 i = 0, count = 1, len = strlen(in), curcount = 0, begin, end;
|
||||
void printToken(lexarToken_t* token) {
|
||||
switch (token->token) {
|
||||
case 1:
|
||||
gfx_printf("%s ", token->text);
|
||||
break;
|
||||
case 6:
|
||||
//printf("%d: '%s'\n", vec.tokens[i].token, vec.tokens[i].text);
|
||||
gfx_printf("\"%s\" ", token->text);
|
||||
break;
|
||||
case 7:
|
||||
//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;
|
||||
}
|
||||
}
|
||||
|
||||
count += countchars(in, ',');
|
||||
scriptResult_t runFunction(scriptCtx_t* ctx) {
|
||||
dictValue_t res = solveEquation(ctx, &ctx->script->tokens[ctx->startEq], ctx->curPos - ctx->startEq);
|
||||
|
||||
if (!count)
|
||||
return 0;
|
||||
|
||||
argv = calloc(count + 1, sizeof(char*));
|
||||
|
||||
while (i < len && curcount < count) {
|
||||
if (in[i] == ' ' || in[i] == ','){
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
begin = i;
|
||||
if (res.varType == ErrType)
|
||||
return scriptResultCreate(res.integer, &ctx->script->tokens[ctx->startEq]);
|
||||
|
||||
while (strrchr(" ,)", in[i]) == NULL){
|
||||
if (in[i] == '"'){
|
||||
begin = i + 1;
|
||||
while (in[++i] != '"'){
|
||||
if (in[i] == '\0')
|
||||
return 0;
|
||||
ctx->startEq = ctx->curPos;
|
||||
if (ctx->varToken.token != Invalid) { // we should not assign null's
|
||||
ctx->varToken.token = Invalid;
|
||||
if (ctx->varIndexSet) {
|
||||
ctx->varIndexSet = 0;
|
||||
dictValue_t* arrayVal = varVectorFind(&ctx->vars, ctx->varToken.text);
|
||||
if (!(arrayVal == NULL || arrayVal->arrayLen <= ctx->varIndex)) {
|
||||
if (arrayVal->varType == IntArrayType && res.varType == IntType) {
|
||||
arrayVal->integerArray[ctx->varIndex] = res.integer;
|
||||
}
|
||||
else if (arrayVal->varType == StringArrayType && res.varType == StringType) {
|
||||
free(arrayVal->stringArray[ctx->varIndex]);
|
||||
arrayVal->stringArray[ctx->varIndex] = res.string;
|
||||
}
|
||||
else if (arrayVal->varType == ByteArrayType && res.varType == IntType) {
|
||||
arrayVal->byteArray[ctx->varIndex] = (u8)(res.integer & 0xFF);
|
||||
}
|
||||
else {
|
||||
return scriptResultCreate(ERRINVALIDTYPE, &ctx->script->tokens[ctx->startEq]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
return scriptResultCreate(ERRNOVAR, &ctx->script->tokens[ctx->startEq]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
varVectorAdd(&ctx->vars, DictCreate(util_cpyStr(ctx->varToken.text), res));
|
||||
}
|
||||
}
|
||||
else {
|
||||
freeDictValueOnVar(res);
|
||||
}
|
||||
|
||||
if (in[i] == '\0')
|
||||
return 0;
|
||||
return scriptResultCreate(0, 0);
|
||||
}
|
||||
|
||||
// TODO
|
||||
// Make sure mem gets free'd properly
|
||||
// Fix bug that custom functions cannot be run from end of script
|
||||
// add arrays
|
||||
|
||||
#define RUNFUNCWITHPANIC(ctx) scriptResult_t res = runFunction(ctx); if (res.resCode != 0) return res
|
||||
|
||||
scriptResult_t mainLoop(scriptCtx_t* ctx) {
|
||||
for (ctx->curPos = 0; ctx->curPos < ctx->script->stored; ctx->curPos++) {
|
||||
u32 i = ctx->curPos;
|
||||
lexarToken_t curToken = ctx->script->tokens[i];
|
||||
//printToken(&curToken);
|
||||
|
||||
if (checkIfVar(ctx->lastToken.token) && curToken.token == Variable) {
|
||||
RUNFUNCWITHPANIC(ctx);
|
||||
}
|
||||
else if (curToken.token == Equal) {
|
||||
// Set last var to lastToken, if lastToken is var
|
||||
|
||||
if (ctx->lastToken.token == RSBracket) {
|
||||
int layer = 0;
|
||||
i = ctx->lastTokenPos - 1;
|
||||
for (; i > 0; i--) {
|
||||
if (ctx->script->tokens[i].token == RSBracket)
|
||||
layer++;
|
||||
else if (ctx->script->tokens[i].token == LSBracket) {
|
||||
if (layer == 0)
|
||||
break;
|
||||
layer--;
|
||||
}
|
||||
}
|
||||
|
||||
i--;
|
||||
|
||||
if (ctx->script->tokens[i].token == Variable) {
|
||||
dictValue_t index = solveEquation(ctx, &ctx->script->tokens[i + 2], ctx->lastTokenPos - i - 2);
|
||||
ctx->lastTokenPos = i;
|
||||
ctx->lastToken = ctx->script->tokens[i];
|
||||
|
||||
if (index.varType == IntType) {
|
||||
ctx->varIndex = index.integer;
|
||||
ctx->varIndexSet = 1;
|
||||
|
||||
if (ctx->varIndexSet) {
|
||||
dictValue_t* arrayVal = varVectorFind(&ctx->vars, ctx->varToken.text);
|
||||
if (arrayVal == NULL) {
|
||||
return scriptResultCreate(ERRSYNTAX, &ctx->script->tokens[ctx->curPos]);
|
||||
}
|
||||
if (ctx->varIndex < 0 || ctx->varIndex >= arrayVal->arrayLen || arrayVal->varType < IntArrayType)
|
||||
return scriptResultCreate(ERRSYNTAX, &ctx->script->tokens[ctx->curPos]);
|
||||
}
|
||||
}
|
||||
else
|
||||
return scriptResultCreate(ERRINVALIDTYPE, &ctx->script->tokens[ctx->curPos]);
|
||||
}
|
||||
else
|
||||
return scriptResultCreate(ERRSYNTAX, &ctx->script->tokens[ctx->curPos]);
|
||||
}
|
||||
|
||||
if (ctx->lastToken.token == Variable) {
|
||||
ctx->startEq = ctx->curPos + 1;
|
||||
ctx->varToken = ctx->lastToken;
|
||||
}
|
||||
else
|
||||
return scriptResultCreate(ERRSYNTAX, &ctx->script->tokens[ctx->curPos]);
|
||||
|
||||
//printf("Setting token %s to next assignment", ctx->lastToken.text);
|
||||
|
||||
// !! check prev for ] for arrays
|
||||
}
|
||||
else if (curToken.token == LBracket) {
|
||||
i++;
|
||||
}
|
||||
int distance = distanceBetweenTokens(&ctx->script->tokens[i], ctx->script->stored - i, LBracket, RBracket);
|
||||
if (distance < 0)
|
||||
return scriptResultCreate(ERRSYNTAX, &ctx->script->tokens[ctx->curPos]);
|
||||
|
||||
end = i;
|
||||
i += distance;
|
||||
ctx->curPos = i;
|
||||
|
||||
if (in[i - 1] == '"'){
|
||||
end--;
|
||||
}
|
||||
|
||||
argv[curcount++] = utils_copyStringSize(in + begin, (u32)(end - begin));
|
||||
}
|
||||
return curcount;
|
||||
}
|
||||
|
||||
FIL scriptin;
|
||||
UINT endByte = 0;
|
||||
int forceExit = false;
|
||||
char currentchar = 0;
|
||||
|
||||
char getnextchar(){
|
||||
f_read(&scriptin, ¤tchar, sizeof(char), &endByte);
|
||||
|
||||
if (sizeof(char) != endByte)
|
||||
forceExit = true;
|
||||
|
||||
//gfx_printf("|%c|", currentchar);
|
||||
return currentchar;
|
||||
}
|
||||
|
||||
void getfollowingchar(char end){
|
||||
while (currentchar != end && !f_eof(&scriptin)){
|
||||
if (currentchar == '"'){
|
||||
while (getnextchar() != '"' && !f_eof(&scriptin));
|
||||
}
|
||||
getnextchar();
|
||||
}
|
||||
}
|
||||
|
||||
void getnextvalidchar(){
|
||||
while ((!((currentchar >= '?' && currentchar <= 'Z') || (currentchar >= 'a' && currentchar <= 'z') || currentchar == '#') && !f_eof(&scriptin)) /*|| currentchar == ';' */)
|
||||
getnextchar();
|
||||
}
|
||||
|
||||
char *makestr(u32 size, char ignore){
|
||||
char *str;
|
||||
u32 count = 0;
|
||||
|
||||
str = calloc(size + 1, sizeof(char));
|
||||
for (u32 i = 0; i < size; i++){
|
||||
getnextchar();
|
||||
if (ignore != 0 && ignore == currentchar)
|
||||
if (ctx->curPos + 1 >= ctx->script->stored && checkIfVar(ctx->lastToken.token)) {
|
||||
solveEquation(ctx, &ctx->script->tokens[ctx->startEq], i + 1 - ctx->startEq);
|
||||
}
|
||||
continue;
|
||||
|
||||
str[count++] = currentchar;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
}
|
||||
else if (curToken.token == LCBracket) {
|
||||
if (ctx->lastToken.token == Equal && ctx->varToken.token == Variable) {
|
||||
varVectorAdd(&ctx->vars, DictCreate(util_cpyStr(ctx->varToken.text), DictValueCreate(JumpType, 0, ctx->curPos)));
|
||||
ctx->varToken.token = Invalid;
|
||||
setCurIndentInstruction(ctx, 1, -1);
|
||||
}
|
||||
|
||||
char *readtilchar(char end, char ignore){
|
||||
FSIZE_t offset, size;
|
||||
if (checkIfVar(ctx->lastToken.token)) {
|
||||
RUNFUNCWITHPANIC(ctx);
|
||||
}
|
||||
|
||||
offset = f_tell(&scriptin);
|
||||
getfollowingchar(end);
|
||||
size = f_tell(&scriptin) - offset;
|
||||
ctx->startEq = ctx->curPos + 1;
|
||||
|
||||
if (size <= 0)
|
||||
return NULL;
|
||||
indentInstructor_t ins = getCurIndentInstruction(ctx);
|
||||
if (ins.active) {
|
||||
if (ins.skip) {
|
||||
int distance = distanceBetweenTokens(&ctx->script->tokens[i + 1], ctx->script->stored - i - 1, LCBracket, RCBracket);
|
||||
if (distance < 0)
|
||||
return scriptResultCreate(ERRSYNTAX, &ctx->script->tokens[ctx->curPos]);
|
||||
ctx->curPos += distance + 1;
|
||||
ctx->startEq = ctx->curPos + 1;
|
||||
}
|
||||
else {
|
||||
ctx->indentLevel++;
|
||||
}
|
||||
}
|
||||
else
|
||||
return scriptResultCreate(ERRINACTIVEINDENT, &ctx->script->tokens[ctx->curPos]);
|
||||
}
|
||||
else if (curToken.token == RCBracket) {
|
||||
if (checkIfVar(ctx->lastToken.token)) {
|
||||
RUNFUNCWITHPANIC(ctx);
|
||||
if (i != ctx->curPos)
|
||||
continue;
|
||||
}
|
||||
|
||||
f_lseek(&scriptin, offset - 1);
|
||||
ctx->indentLevel--;
|
||||
|
||||
return makestr((u32)size, ignore);
|
||||
}
|
||||
indentInstructor_t ins = getCurIndentInstruction(ctx);
|
||||
if (ins.active && ins.jump) {
|
||||
ctx->curPos = ins.jumpLoc - 1;
|
||||
}
|
||||
|
||||
|
||||
char *funcbuff = NULL;
|
||||
void functionparser(){
|
||||
char *unsplitargs;
|
||||
|
||||
/*
|
||||
if (funcbuff != NULL)
|
||||
free(funcbuff);
|
||||
*/
|
||||
|
||||
funcbuff = readtilchar('(', ' ');
|
||||
|
||||
getfollowingchar('(');
|
||||
getnextchar();
|
||||
|
||||
unsplitargs = readtilchar(')', 0);
|
||||
|
||||
if (unsplitargs != NULL){
|
||||
argc = splitargs(unsplitargs);
|
||||
getnextchar();
|
||||
}
|
||||
else {
|
||||
argc = 0;
|
||||
}
|
||||
getnextchar();
|
||||
|
||||
free(unsplitargs);
|
||||
}
|
||||
|
||||
char *gettargetvar(){
|
||||
char *variable = NULL;
|
||||
|
||||
variable = readtilchar('=', ' ');
|
||||
|
||||
getfollowingchar('=');
|
||||
getnextchar();
|
||||
|
||||
return variable;
|
||||
}
|
||||
|
||||
void mainparser(){
|
||||
char *variable = NULL;
|
||||
int res, out = 0;
|
||||
|
||||
getnextvalidchar();
|
||||
|
||||
if (f_eof(&scriptin))
|
||||
return;
|
||||
|
||||
if (currentchar == '#'){
|
||||
getfollowingchar('\n');
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentchar == '@'){
|
||||
variable = gettargetvar();
|
||||
getnextvalidchar();
|
||||
}
|
||||
|
||||
functionparser();
|
||||
|
||||
res = run_function(funcbuff, &out);
|
||||
if (res < 0){
|
||||
printerrors = true;
|
||||
//gfx_printf("%s|%s|%d", funcbuff, argv[0], argc);
|
||||
//btn_wait();
|
||||
int lineNumber = 1;
|
||||
u64 end = f_tell(&scriptin);
|
||||
f_lseek(&scriptin, 0);
|
||||
|
||||
while (f_tell(&scriptin) < end && !f_eof(&scriptin)){
|
||||
if (getnextchar() == '\n')
|
||||
lineNumber++;
|
||||
ctx->startEq = ctx->curPos + 1;
|
||||
}
|
||||
else if (ctx->curPos + 1 >= ctx->script->stored && checkIfVar(ctx->lastToken.token)) {
|
||||
solveEquation(ctx, &ctx->script->tokens[ctx->startEq], i + 1 - ctx->startEq);
|
||||
}
|
||||
|
||||
gfx_errDisplay((res == -1) ? funcbuff : "run_function", (res == -1) ? ERR_IN_FUNC : ERR_SCRIPT_LOOKUP_FAIL, lineNumber);
|
||||
forceExit = true;
|
||||
//gfx_printf("Func: %s\nArg1: %s\n", funcbuff, argv[0]);
|
||||
}
|
||||
else {
|
||||
str_int_add("@RESULT", out);
|
||||
|
||||
if (variable != NULL)
|
||||
str_int_add(variable, out);
|
||||
ctx->lastToken = ctx->script->tokens[ctx->curPos];
|
||||
ctx->lastTokenPos = ctx->curPos;
|
||||
}
|
||||
|
||||
//gfx_printf("\nGoing to next func %c\n", currentchar);
|
||||
|
||||
if (funcbuff != NULL){
|
||||
free(funcbuff);
|
||||
funcbuff = NULL;
|
||||
}
|
||||
|
||||
if (argv != NULL) {
|
||||
for (int i = 0; argv[i] != NULL; i++)
|
||||
free(argv[i]);
|
||||
free(argv);
|
||||
argv = NULL;
|
||||
}
|
||||
|
||||
if (variable != NULL){
|
||||
free(variable);
|
||||
}
|
||||
return scriptResultCreate(0, 0);
|
||||
}
|
||||
|
||||
void skipbrackets(){
|
||||
u32 bracketcounter = 0;
|
||||
const char* functionFails[] = {
|
||||
"An invalid operation was performed",
|
||||
"Double Nots are not allowed",
|
||||
"A syntax error was found",
|
||||
"The recieved type was incorrect",
|
||||
"The variable could not be found",
|
||||
"The specified function could not be found",
|
||||
"An inactive indent was found"
|
||||
};
|
||||
|
||||
getfollowingchar('{');
|
||||
getnextchar();
|
||||
void startScript(char* path) {
|
||||
char* file = sd_file_read(path, NULL);
|
||||
|
||||
while ((currentchar != '}' || bracketcounter != 0) && !f_eof(&scriptin)){
|
||||
if (currentchar == '{')
|
||||
bracketcounter++;
|
||||
else if (currentchar == '}')
|
||||
bracketcounter--;
|
||||
|
||||
getnextchar();
|
||||
}
|
||||
}
|
||||
|
||||
extern u32 currentcolor;
|
||||
extern char *currentpath;
|
||||
void runScript(char *path){
|
||||
int res;
|
||||
char *path_local = NULL;
|
||||
forceExit = false;
|
||||
currentchar = 0;
|
||||
currentcolor = COLOR_WHITE;
|
||||
gfx_clearscreen();
|
||||
utils_copystring(path, &path_local);
|
||||
|
||||
res = f_open(&scriptin, path, FA_READ | FA_OPEN_EXISTING);
|
||||
if (res != FR_OK){
|
||||
gfx_errDisplay("ParseScript", res, 1);
|
||||
if (file == NULL)
|
||||
return;
|
||||
|
||||
gfx_clearscreen();
|
||||
|
||||
scriptCtx_t ctx = createScriptCtx();
|
||||
lexarVector_t vec = lexarGo(file);
|
||||
free(file);
|
||||
ctx.script = &vec;
|
||||
|
||||
scriptResult_t res = mainLoop(&ctx);
|
||||
gfx_printf("end of script\n");
|
||||
|
||||
if (res.resCode) {
|
||||
gfx_printf("[ERROR] %d\n%s\nNear:", res.resCode, functionFails[res.resCode - 1]);
|
||||
printToken(res.nearToken);
|
||||
}
|
||||
|
||||
printerrors = false;
|
||||
|
||||
//add builtin vars
|
||||
str_int_add("@EMUMMC", emu_cfg.enabled);
|
||||
str_int_add("@RESULT", 0);
|
||||
str_int_add("@JOYCONN", hidConnected());
|
||||
str_str_add("$CURRENTPATH", currentpath);
|
||||
|
||||
//str_int_printall();
|
||||
|
||||
while (!f_eof(&scriptin) && !forceExit){
|
||||
mainparser();
|
||||
}
|
||||
|
||||
printerrors = true;
|
||||
//str_int_printall();
|
||||
|
||||
f_close(&scriptin);
|
||||
str_int_clear();
|
||||
//str_jmp_clear();
|
||||
str_str_clear();
|
||||
free(path_local);
|
||||
//btn_wait();
|
||||
|
||||
gfx_printf("\n\n");
|
||||
//mainLoop2(&ctx, &vec);
|
||||
lexarVectorClear(&vec);
|
||||
destroyScriptCtx(&ctx);
|
||||
hidWait();
|
||||
}
|
||||
Reference in New Issue
Block a user