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
This commit is contained in:
phobos2077
2024-06-09 17:26:09 +02:00
parent 500cd103b2
commit 3bf82984f3
5 changed files with 72 additions and 116 deletions
+1
View File
@@ -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 (<symbol> in <expression>)`.
- You can declare varaibles in-place by adding `variable` keyword before symbol name.
- new:
```
procedure bingle begin
+52 -99
View File
@@ -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) {
+3 -1
View File
@@ -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
+16 -5
View File
@@ -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);
-11
View File
@@ -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);