From 3bf82984f3836199c055e6500b2f61f0cda361fb Mon Sep 17 00:00:00 2001 From: phobos2077 Date: Sun, 9 Jun 2024 17:26:09 +0200 Subject: [PATCH] Syntax improvements: foreach, for, variables - ForEach: allow to declare variables for key & value header - ForEach: allow to use expression after `in` that start with a symbol without mandatory parantheses - Variables: allow to declare variables anywhere where statement is expected - Variables: simplify declaration code & array vars - Expressions: display useful error message when expression was expected but nothing was parsed --- docs/sslc_readme.md | 1 + parse.c | 151 +++++++++++++++----------------------------- parse.h | 4 +- parseext.c | 21 ++++-- parseext.h | 11 ---- 5 files changed, 72 insertions(+), 116 deletions(-) diff --git a/docs/sslc_readme.md b/docs/sslc_readme.md index fa8d515..6b017f2 100644 --- a/docs/sslc_readme.md +++ b/docs/sslc_readme.md @@ -288,6 +288,7 @@ Syntax which requires sfall for compiled scripts to be interpreted is marked by __NOTE:__ When using incremental operators like `+=`, `*=`, `++`, `--` compiler will use additional temp variable to get an array at penultimate level in order to avoid making the same chain of `get_array` calls twice. - (*) `foreach` loops: A shorthand method of looping over all elements in an array. Syntax is `foreach ( in )`. + - You can declare varaibles in-place by adding `variable` keyword before symbol name. - new: ``` procedure bingle begin diff --git a/parse.c b/parse.c index 9d6757c..9cf0254 100644 --- a/parse.c +++ b/parse.c @@ -59,7 +59,6 @@ static void freeVariableList(VariableList *v); static void freeVariable(Variable *v); static void parseWhile(Procedure *p, NodeList *n); static int writeBlock(NodeList *n, int i, FILE *f); -static int variable(VariableList *v, char **names, int type, ArrayVarList* arrays, int allowMulti); extern FILE* parseroutput; @@ -498,7 +497,7 @@ static void referenceProcedure(ProcedureList *p, int which) { reference(&p->procedures[which].numRefs, &p->procedures[which].references); } -static int addVariable(VariableList *var, char **namelist, int type, char *name) { +int addVariable(VariableList *var, char **namelist, int type, char *name) { Variable *v = var->variables; int i; @@ -526,7 +525,6 @@ static int addVariable(VariableList *var, char **namelist, int type, char *name) v[i].uses = 0; v[i].numRefs = 0; v[i].references = 0; - v[i].arrayLen = -1; v[i].initialized = 0; v[i].declared = lexGetLineno(currentInputStream); v[i].fdeclared = lexGetFilename(currentInputStream); @@ -542,23 +540,10 @@ void GenTmpVar(Procedure *p, LexData* lex) { addVariable(&p->variables, &p->namelist, V_LOCAL, lex->stringData); } -static void AddArrayVar(ArrayVarList* arrays, ArrayVar* var) { - if (arrays->size == 0) { - arrays->vars = (ArrayVar*)malloc(sizeof(ArrayVar) * 4); - arrays->size = 4; - } else if (arrays->size == arrays->count) { - arrays->size += 4; - arrays->vars = (ArrayVar*)malloc(sizeof(ArrayVar) * arrays->size); - } - arrays->vars[arrays->count].name = (char*)malloc(strlen(var->name) + 1); - strcpy(arrays->vars[arrays->count].name, var->name); - arrays->vars[arrays->count].len = var->len; - arrays->vars[arrays->count++].datasize = var->datasize; -} -static int defineVariable(VariableList *v, char **namelist, int type, ArrayVarList* arrays, int allowMulti) { - int i; - ArrayVar av; +static int defineVariable(VariableList *v, char **namelist, int type, char allowArrays, int allowMulti) { + int i, arraySize, arrayFlags; LexData symbol; + Procedure* p; do { if (expectToken(T_SYMBOL) == -1) @@ -575,19 +560,33 @@ static int defineVariable(VariableList *v, char **namelist, int type, ArrayVarLi parseSemanticError("Couldn't add variable %s.", lexData.stringData); if (expectToken('[') != -1) { - if (!arrays) parseSemanticError("Array variable declarations not allowed here."); - av.name = lexData.stringData; - av.datasize = 4; + if (!allowArrays) parseSemanticError("Array variable declarations not allowed here."); if (expectToken(T_CONSTANT) == -1) parseError("Initialization of array bounds with non-constant."); if (lexData.type != T_INT) parseError("Initialization of array bounds with non-integer."); - av.len = lexData.intData; + arraySize = lexData.intData; if (expectToken(',') != -1) { - if (expectToken(T_CONSTANT) == -1) parseError("Initialization of array data size with non-constant."); - if (lexData.type != T_INT) parseError("Initialization of array data size with non-integer."); - av.datasize = lexData.intData; + if (expectToken(T_CONSTANT) == -1) parseError("Initialization of array flags with non-constant."); + if (lexData.type != T_INT) parseError("Initialization of array flags with non-integer."); + arrayFlags = lexData.intData; } + else arrayFlags = 4; + if (expectToken(']') == -1) parseError("Expected ']'"); - AddArrayVar(arrays, &av); + + p = currentProcedure; + emitOp(p, &p->nodes, T_START_STATEMENT); + emitNode(p, &p->nodes, &symbol); + emitOp(p, &p->nodes, T_ASSIGN); + emitOp(p, &p->nodes, T_START_EXPRESSION); + emitOp(p, &p->nodes, T_TS_TEMP_ARRAY); + emitOp(p, &p->nodes, T_START_EXPRESSION); + emitInt(p, &p->nodes, arraySize); + emitOp(p, &p->nodes, T_END_EXPRESSION); + emitOp(p, &p->nodes, T_START_EXPRESSION); + emitInt(p, &p->nodes, arrayFlags); + emitOp(p, &p->nodes, T_END_EXPRESSION); + emitOp(p, &p->nodes, T_END_EXPRESSION); + emitOp(p, &p->nodes, T_END_STATEMENT); } else if (expectToken(T_ASSIGN) != -1) { char buf[1024]; int allowExpr = (allowMulti && type == V_LOCAL); @@ -610,7 +609,7 @@ static int defineVariable(VariableList *v, char **namelist, int type, ArrayVarLi } } while (allowMulti && expectToken(',') != -1); if (expectToken(';') == -1) { - if (arrays && backwardcompat == 0) parseError("Expected ';' at end of variable declaration."); + if (allowArrays && backwardcompat == 0) parseError("Expected ';' at end of variable declaration."); } return 0; } @@ -780,7 +779,6 @@ static int externVariable(VariableList *v, char **namelist, int type, int flag) i = addVariable(v, namelist, type, lexData.stringData); - v->variables[i].arrayLen = -1; v->variables[i].declared = lexGetLineno(currentInputStream); v->variables[i].fdeclared = lexGetFilename(currentInputStream); @@ -800,7 +798,7 @@ static int externVariable(VariableList *v, char **namelist, int type, int flag) return 0; } -static int findVariableIndex(char *var, VariableList *v, char *namelist) { +int findVariableIndex(char *var, VariableList *v, char *namelist) { int i; for (i = 0; i < v->numVariables; ++i) { @@ -885,41 +883,22 @@ static int export(Program *p, char **names) { } /* Parse the syntax for declaring global and local variables of the procedures */ -static int variable(VariableList *v, char **names, int type, ArrayVarList* arrays, int allowMulti) { +static int variable(VariableList *v, char **names, int type, char allowArrays, int allowMulti) { if (expectToken(T_VARIABLE) == -1) return 1; - do { - if (expectToken(T_BEGIN) != -1) { // sfall addition - while (expectToken(T_END) == -1) { - if (defineVariable(v, names, type, arrays, allowMulti)) - return 1; - } - } else if (expectToken(T_SYMBOL) != -1) { - ungetToken(); - if (defineVariable(v, names, type, arrays, allowMulti)) + if (expectToken(T_BEGIN) != -1) { // sfall addition + if (!allowMulti) parseError("Unexpected 'begin' block."); + while (expectToken(T_END) == -1) { + if (defineVariable(v, names, type, allowArrays, allowMulti)) return 1; - } else - parseError("Expected variable name symbol or 'begin' block."); - } while (expectToken(T_VARIABLE) != -1); + } + } else if (expectToken(T_SYMBOL) != -1) { + ungetToken(); + if (defineVariable(v, names, type, allowArrays, allowMulti)) + return 1; + } else + parseError("Expected variable name symbol or 'begin' block."); - ungetToken(); // put back what was there - return 0; -} - -/* - Parse the syntax for declaring local variables in the procedure body without the 'begin...end' block - added sfall 4.2.7 -*/ -static int VariableParse(VariableList *v, char **names, int type, ArrayVarList* arrays) { - do { - if (expectToken(T_SYMBOL) != -1) { - ungetToken(); - if (defineVariable(v, names, type, arrays, 1)) return 1; - } else - parseError("Expected variable name symbol."); - } while (expectToken(T_VARIABLE) != -1); - - ungetToken(); // put back what was there return 0; } @@ -1044,7 +1023,7 @@ static void parseVariableRef(Procedure *p, NodeList *nodes, LexData* d, int refS } static void factor(Procedure *p, NodeList *nodes) { - int i, refSyntax = 0; + int i, refSyntax = 0, numNodes = nodes->numNodes; i = lex(); if (i == '@') { @@ -1140,6 +1119,9 @@ static void factor(Procedure *p, NodeList *nodes) { break; default: parseLibExpression(p, nodes, i); + if (nodes->numNodes == numNodes) { + parseError("Expression expected."); + } break; } } @@ -1602,66 +1584,37 @@ static void parseStatementInternal(Procedure *p, char requireSemicolon) { emitOp(p, &p->nodes, T_END_STATEMENT); } +static void parseStatementOrLocalVariables(Procedure *p, char requireSemicolon) { + if (variable(&p->variables, &p->namelist, V_LOCAL, 1, 1)) + parseStatementInternal(p, requireSemicolon); +} + void parseStatement(Procedure *p) { - parseStatementInternal(p, 1); + parseStatementOrLocalVariables(p, 1); } // sfall addition void parseStatementNoSemicolon(Procedure *p) { - parseStatementInternal(p, 0); + parseStatementOrLocalVariables(p, 0); } static void parseBlock(Procedure *p) { int i; - ArrayVarList arrays; - LexData tlex; - arrays.vars = 0; - arrays.size = 0; - arrays.count = 0; if (expectToken(T_BEGIN) == -1) parseError("expected 'begin'."); emitNode(p, &p->nodes, &lexData); // emit the begin - variable(&p->variables, &p->namelist, V_LOCAL, &arrays, 1); - - for(i = 0; i < arrays.count; i++) { - emitOp(p, &p->nodes, T_START_STATEMENT); - tlex.token = T_SYMBOL; - tlex.stringData = arrays.vars[i].name; - emitNode(p, &p->nodes, &tlex); - emitOp(p, &p->nodes, T_ASSIGN); - emitOp(p, &p->nodes, T_START_EXPRESSION); - emitOp(p, &p->nodes, T_TS_TEMP_ARRAY); - emitOp(p, &p->nodes, T_START_EXPRESSION); - emitInt(p, &p->nodes, arrays.vars[i].len); - emitOp(p, &p->nodes, T_END_EXPRESSION); - emitOp(p, &p->nodes, T_START_EXPRESSION); - emitInt(p, &p->nodes, arrays.vars[i].datasize); - emitOp(p, &p->nodes, T_END_EXPRESSION); - emitOp(p, &p->nodes, T_END_EXPRESSION); - emitOp(p, &p->nodes, T_END_STATEMENT); - } - while ((i = lex()) != T_END) { - if (i == T_EOF) + if (i == T_EOF) { parseError("Premature EOF encountered."); - else if (i == T_VARIABLE) { // sfall addition (Fakels) - VariableParse(&p->variables, &p->namelist, V_LOCAL, &arrays); } else { ungetToken(); parseStatement(p); } } emitNode(p, &p->nodes, &lexData); // emit the end - - if (arrays.vars) { - for(i = 0; i < arrays.count; i++) { - free(arrays.vars[i].name); - } - free(arrays.vars); - } } static void parseIf(Procedure *p, NodeList *n) { diff --git a/parse.h b/parse.h index 2eb0652..3432bf4 100644 --- a/parse.h +++ b/parse.h @@ -45,7 +45,6 @@ typedef struct { int numRefs; Value value; int type; // this type is where it was declared - int arrayLen; int declared; const char* fdeclared; int uses; @@ -154,6 +153,9 @@ extern int expectToken(int expectToken); extern void freeCurrentProgram(void); extern char *getName(int offset, char *namelist); +extern int addVariable(VariableList *var, char **namelist, int type, char *name); +extern int findVariableIndex(char *var, VariableList *v, char *namelist); + #define P_GLOBAL 0x80000000 #define P_LOCAL 0x40000000 #define P_PROCEDURE 0x20000000 diff --git a/parseext.c b/parseext.c index ee829a1..1768da1 100644 --- a/parseext.c +++ b/parseext.c @@ -205,34 +205,45 @@ void parseFor(Procedure *p, NodeList *n) { void parseForEach(Procedure *p, NodeList *n) { LexData symbolKey, symbolVal, a, len, count; - char hasKey = 0, emitEnd = 0, hasParan = 0; + char hasKey = 0, emitEnd = 0, hasParan = 0, isSymbol = 0, addVars = 0; if (expectToken('(') != -1) { hasParan = 1; } + if (expectToken(T_VARIABLE) != -1) { + addVars = 1; + } if (expectToken(T_SYMBOL) == -1) parseError("Expected symbol"); CloneLexData(&symbolVal, &lexData); + if (addVars && addVariable(&p->variables, &p->namelist, V_LOCAL, lexData.stringData) == -1) { + parseSemanticError("Couldn't add variable %s.", lexData.stringData); + } if (expectToken(':') != -1) { symbolKey = symbolVal; if(expectToken(T_SYMBOL) == -1) parseError("Expected symbol for value"); CloneLexData(&symbolVal, &lexData); + if (addVars && addVariable(&p->variables, &p->namelist, V_LOCAL, lexData.stringData) == -1) { + parseSemanticError("Couldn't add variable %s.", lexData.stringData); + } hasKey = 1; } if (expectToken(T_IN) == -1) parseError("Expected 'in'"); - if (expectToken(T_SYMBOL) == -1) { + isSymbol = expectToken(T_SYMBOL) != -1; + if (isSymbol && findVariableIndex(lexData.stringData, &p->variables, p->namelist) != -1) { + CloneLexData(&a, &lexData); + } else { + if (isSymbol) ungetToken(); GenTmpVar(p, &a); emitOp(p, n, T_START_STATEMENT); emitNode(p, n, &a); emitOp(p, n, T_ASSIGN); parseExpression(p, n); emitOp(p, n, T_END_STATEMENT); - } else { - CloneLexData(&a, &lexData); } GenTmpVar(p, &len); GenTmpVar(p, &count); - if (!hasKey) GenTmpVar(p, &symbolKey); + if (!hasKey && !addVars) GenTmpVar(p, &symbolKey); //count:=0; emitOp(p, n, T_START_STATEMENT); diff --git a/parseext.h b/parseext.h index 9728902..be4adfc 100644 --- a/parseext.h +++ b/parseext.h @@ -5,17 +5,6 @@ Extended SSL syntax for sfall */ -typedef struct { - char* name; - int len; - int datasize; -} ArrayVar; -typedef struct { - ArrayVar* vars; - int count; - int size; -} ArrayVarList; - void appendNodeListPart(NodeList* dst, const NodeList* src, int offset, int length); void appendNodeList(NodeList* dst, const NodeList* src);