mirror of
https://github.com/sfall-team/sslc.git
synced 2026-07-27 16:52:49 -07:00
496 lines
14 KiB
C
496 lines
14 KiB
C
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "parse.h"
|
|
#include "parselib.h"
|
|
#include "extra.h"
|
|
|
|
#include "parseext.h"
|
|
|
|
extern int loopNesting;
|
|
extern Program *currentProgram;
|
|
|
|
static int arrayExpressionNesting = 0;
|
|
|
|
#define ARRAYFLAG_EXPR_PUSH (32) // is created as part of array sub-expression
|
|
#define ARRAYFLAG_EXPR_POP (64) // is used to indicate end of array sub-expression, not used in actual array
|
|
|
|
// vars, constants, etc.
|
|
void emitNodeExpr(Procedure *p, NodeList *n, LexData *data) {
|
|
emitOp(p, n, T_START_EXPRESSION);
|
|
emitNode(p, n, data);
|
|
emitOp(p, n, T_END_EXPRESSION);
|
|
}
|
|
|
|
void appendNodeListPart(NodeList* dst, const NodeList* src, int offset, int length) {
|
|
dst->nodes = realloc(dst->nodes, sizeof(Node) * (dst->numNodes + length + 9));
|
|
memcpy(&dst->nodes[dst->numNodes], &src->nodes[offset], sizeof(Node) * (length));
|
|
dst->numNodes += length;
|
|
}
|
|
|
|
void appendNodeList(NodeList* dst, const NodeList* src) {
|
|
appendNodeListPart(dst, src, 0, src->numNodes);
|
|
}
|
|
|
|
|
|
int parseArrayDereference(Procedure *p, NodeList *nodes, LexData symb, int *lastExprSize) {
|
|
NodeList tmpN;
|
|
LexData d;
|
|
int dotSyntax, nodesBefore, derefCount = 0;
|
|
tmpN.nodes = 0;
|
|
tmpN.numNodes = 0;
|
|
do { // write "get_array(" on each iteration to main nodes stream while writing the ending part to the temp stream
|
|
derefCount++;
|
|
dotSyntax = (lexData.token == '.');
|
|
emitOp(p, nodes, T_TS_GET_ARRAY);
|
|
emitOp(p, nodes, T_START_EXPRESSION);
|
|
if (tmpN.numNodes > 0) {
|
|
emitOp(p, &tmpN, T_END_EXPRESSION); // end of previous expression
|
|
} else { // first iteration
|
|
emitNode(p, &tmpN, &symb);
|
|
emitOp(p, &tmpN, T_END_EXPRESSION);
|
|
}
|
|
nodesBefore = tmpN.numNodes;
|
|
if (dotSyntax) {
|
|
if (expectToken(T_SYMBOL) == -1) {
|
|
parseError("Expected symbol");
|
|
}
|
|
d = lexData; // convert symbol to string constant
|
|
d.token = T_CONSTANT;
|
|
d.type = T_STRING;
|
|
emitOp(p, &tmpN, T_START_EXPRESSION);
|
|
emitNode(p, &tmpN, &d);
|
|
emitOp(p, &tmpN, T_END_EXPRESSION);
|
|
} else {
|
|
parseExpression(p, &tmpN);
|
|
if (expectToken(']') == -1) {
|
|
parseError("Expected ']'");
|
|
}
|
|
}
|
|
if (lastExprSize) *lastExprSize = tmpN.numNodes - nodesBefore;
|
|
} while (expectToken('.') != -1 || expectToken('[') != -1);
|
|
if (tmpN.numNodes > 0) { // append cached nodes
|
|
appendNodeList(nodes, &tmpN);
|
|
free(tmpN.nodes);
|
|
}
|
|
return derefCount;
|
|
}
|
|
|
|
void parseArrayAssignment(Procedure *p, NodeList *nodes, LexData symb) {
|
|
int t, numDeref, op, lastExprSize = 0, nIndex = 0;
|
|
LexData d, tmpVar, tmpVarArr;
|
|
NodeList tmpN;
|
|
|
|
tmpN.nodes = 0;
|
|
tmpN.numNodes = 0;
|
|
numDeref = parseArrayDereference(p, &tmpN, symb, &lastExprSize);
|
|
t = lex();
|
|
if (t == T_INC || t == T_DEC) { // pretend it's += or -=
|
|
t = (t == T_INC) ? T_ASSIGN_ADD : T_ASSIGN_SUB;
|
|
d.token = T_CONSTANT;
|
|
d.type = T_INT;
|
|
d.intData = 1;
|
|
setNextToken(&d);
|
|
}
|
|
switch(t) {
|
|
case T_ASSIGN:
|
|
tmpN.nodes[0].token = T_TS_SET_ARRAY;
|
|
appendNodeList(nodes, &tmpN);
|
|
parseExpression(p, nodes); // expr
|
|
break;
|
|
case T_ASSIGN_ADD:
|
|
case T_ASSIGN_SUB:
|
|
case T_ASSIGN_DIV:
|
|
case T_ASSIGN_MUL:
|
|
switch(t) {
|
|
case T_ASSIGN_ADD: op = '+'; break;
|
|
case T_ASSIGN_MUL: op = '*'; break;
|
|
case T_ASSIGN_SUB: op = '-'; break;
|
|
case T_ASSIGN_DIV: op = '/'; break;
|
|
}
|
|
tmpVar.token = tmpVarArr.token = 0;
|
|
if (numDeref > 1) { // multidimensional access - need tmpVar to hold deepest array
|
|
GenTmpVar(p, &tmpVarArr); // assign index of last minus one array to tmp var
|
|
// tmp := get_array(....)
|
|
emitNode(p, nodes, &tmpVarArr);
|
|
emitOp(p, nodes, T_ASSIGN);
|
|
appendNodeListPart(nodes, &tmpN, 1, tmpN.numNodes - lastExprSize - 1);
|
|
emitOp(p, nodes, T_END_STATEMENT);
|
|
emitOp(p, nodes, T_START_STATEMENT);
|
|
}
|
|
nIndex = tmpN.numNodes - lastExprSize + 1; // points to first node in array index after START_EXPRESSION
|
|
if (lastExprSize > 3 || (tmpN.nodes[nIndex].token != T_SYMBOL && tmpN.nodes[nIndex].token != T_CONSTANT)) { // if index is a complex expression
|
|
GenTmpVar(p, &tmpVar); // assign element index to tmp var
|
|
// tmp := (expression)
|
|
emitNode(p, nodes, &tmpVar);
|
|
emitOp(p, nodes, T_ASSIGN);
|
|
appendNodeListPart(nodes, &tmpN, tmpN.numNodes - lastExprSize, lastExprSize); // index expr
|
|
emitOp(p, nodes, T_END_STATEMENT);
|
|
emitOp(p, nodes, T_START_STATEMENT);
|
|
}
|
|
// set_array(tmpVarArr/symb, lastExpr/tmpVar, get_array(tmpVarArr/symb, lastExpr/tmpVar) OP NEXT_EXPRESSION)
|
|
emitOp(p, nodes, T_TS_SET_ARRAY);
|
|
if (tmpVarArr.token) {
|
|
emitNodeExpr(p, nodes, &tmpVarArr); // last array
|
|
} else {
|
|
appendNodeListPart(nodes, &tmpN, 1, 3); // array symbol expr
|
|
}
|
|
if (tmpVar.token) {
|
|
emitNodeExpr(p, nodes, &tmpVar); // last index tmp var
|
|
} else {
|
|
appendNodeListPart(nodes, &tmpN, tmpN.numNodes - lastExprSize, lastExprSize); // index symbol/constant
|
|
}
|
|
emitOp(p, nodes, T_START_EXPRESSION); // binary operator
|
|
emitOp(p, nodes, T_START_EXPRESSION); // get_array
|
|
emitOp(p, nodes, T_TS_GET_ARRAY);
|
|
// same sequence as above...
|
|
if (tmpVarArr.token) {
|
|
emitNodeExpr(p, nodes, &tmpVarArr); // last array
|
|
} else {
|
|
appendNodeListPart(nodes, &tmpN, 1, 3); // array symbol expr
|
|
}
|
|
if (tmpVar.token) {
|
|
emitNodeExpr(p, nodes, &tmpVar); // last index tmp var
|
|
} else {
|
|
appendNodeListPart(nodes, &tmpN, tmpN.numNodes - lastExprSize, lastExprSize); // index symbol/constant
|
|
}
|
|
emitOp(p, nodes, T_END_EXPRESSION);
|
|
parseExpression(p, nodes); // second argument
|
|
emitOp(p, nodes, op); // operator
|
|
emitOp(p, nodes, T_END_EXPRESSION);
|
|
break;
|
|
default:
|
|
parseError("Assignment operator expected (array).");
|
|
}
|
|
free(tmpN.nodes);
|
|
}
|
|
|
|
|
|
void parseFor(Procedure *p, NodeList *n) {
|
|
int hadbracket=0;
|
|
NodeList tmp, tmp2;
|
|
if(expectToken('(') != -1) hadbracket=1;
|
|
parseStatement(p);
|
|
|
|
emitOp(p, n, T_START_STATEMENT);
|
|
emitOp(p, n, T_WHILE);
|
|
parseExpression(p, n);
|
|
if(expectToken(';') == -1) parseError("Expected ';'");
|
|
emitOp(p, n, T_DO);
|
|
emitOp(p, n, T_START_STATEMENT);
|
|
emitOp(p, n, T_BEGIN);
|
|
|
|
tmp=*n;
|
|
n->nodes=0;
|
|
n->numNodes=0;
|
|
parseStatementNoSemicolon(p);
|
|
if (expectToken(';') == -1 && !hadbracket) {
|
|
parseError("Expected ';'");
|
|
}
|
|
if(hadbracket&&expectToken(')') == -1) {
|
|
parseError("Expected ')'");
|
|
}
|
|
tmp2.numNodes=n->numNodes;
|
|
tmp2.nodes=n->nodes;
|
|
n->numNodes=tmp.numNodes;
|
|
n->nodes=tmp.nodes;
|
|
loopNesting++;
|
|
parseStatement(p);
|
|
loopNesting--;
|
|
// special marker for code generator
|
|
emitOp(p, n, T_START_STATEMENT);
|
|
emitOp(p, n, T_LOOP_END);
|
|
emitOp(p, n, T_END_STATEMENT);
|
|
appendNodeList(n, &tmp2); // append post-loop increment part
|
|
|
|
emitOp(p, n, T_END);
|
|
emitOp(p, n, T_END_STATEMENT);
|
|
emitOp(p, n, T_END_STATEMENT);
|
|
free(tmp2.nodes);
|
|
}
|
|
|
|
|
|
void parseForEach(Procedure *p, NodeList *n) {
|
|
LexData symbolKey, symbolVal, a, len, count;
|
|
NodeList tmpN, arrayVar;
|
|
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'");
|
|
|
|
// Optimization: if expression is simple variable access, use it directly in loop body without temp var.
|
|
tmpN.nodes = 0;
|
|
tmpN.numNodes = 0;
|
|
arrayVar.nodes = 0;
|
|
arrayVar.numNodes = 0;
|
|
parseExpression(p, &tmpN);
|
|
if (tmpN.numNodes == 3 && tmpN.nodes[1].token == T_SYMBOL && (tmpN.nodes[1].value.type & P_PROCEDURE) == 0) {
|
|
appendNodeListPart(&arrayVar, &tmpN, 1, 1);
|
|
} else {
|
|
GenTmpVar(p, &a);
|
|
emitNode(p, &arrayVar, &a);
|
|
free(a.stringData);
|
|
|
|
emitOp(p, n, T_START_STATEMENT);
|
|
appendNodeList(n, &arrayVar);
|
|
emitOp(p, n, T_ASSIGN);
|
|
appendNodeList(n, &tmpN);
|
|
emitOp(p, n, T_END_STATEMENT);
|
|
}
|
|
|
|
GenTmpVar(p, &len);
|
|
GenTmpVar(p, &count);
|
|
if (!hasKey) GenTmpVar(p, &symbolKey);
|
|
|
|
//count:=0;
|
|
emitOp(p, n, T_START_STATEMENT);
|
|
emitNode(p, n, &count);
|
|
emitOp(p, n, T_ASSIGN);
|
|
emitOp(p, n, T_START_EXPRESSION);
|
|
emitInt(p, n, 0);
|
|
emitOp(p, n, T_END_EXPRESSION);
|
|
emitOp(p, n, T_END_STATEMENT);
|
|
|
|
//len:=len_array(a);
|
|
emitOp(p, n, T_START_STATEMENT);
|
|
emitNode(p, n, &len);
|
|
emitOp(p, n, T_ASSIGN);
|
|
emitOp(p, n, T_START_EXPRESSION);
|
|
emitOp(p, n, T_TS_LEN_ARRAY);
|
|
emitOp(p, n, T_START_EXPRESSION);
|
|
appendNodeList(n, &arrayVar);
|
|
emitOp(p, n, T_END_EXPRESSION);
|
|
emitOp(p, n, T_END_EXPRESSION);
|
|
emitOp(p, n, T_END_STATEMENT);
|
|
|
|
//while count < len do begin
|
|
emitOp(p, n, T_START_STATEMENT);
|
|
emitOp(p, n, T_WHILE);
|
|
emitOp(p, n, T_START_EXPRESSION);
|
|
emitNode(p, n, &count);
|
|
emitNode(p, n, &len);
|
|
emitOp(p, n, '<');
|
|
if(expectToken(T_WHILE) != -1) { // optional "while" condition
|
|
emitOp(p, n, T_AND);
|
|
parseExpression(p, n);
|
|
}
|
|
if(hasParan && (expectToken(')') == -1)) {
|
|
parseError("Expected )");
|
|
}
|
|
emitOp(p, n, T_END_EXPRESSION);
|
|
emitOp(p, n, T_DO);
|
|
emitOp(p, n, T_START_STATEMENT);
|
|
emitOp(p, n, T_BEGIN);
|
|
|
|
//symbolKey:=get_array_key(a, count);
|
|
emitOp(p, n, T_START_STATEMENT);
|
|
emitNode(p, n, &symbolKey);
|
|
emitOp(p, n, T_ASSIGN);
|
|
emitOp(p, n, T_START_EXPRESSION);
|
|
emitOp(p, n, T_TS_GET_ARRAY_KEY);
|
|
emitOp(p, n, T_START_EXPRESSION);
|
|
appendNodeList(n, &arrayVar);
|
|
emitOp(p, n, T_END_EXPRESSION);
|
|
emitOp(p, n, T_START_EXPRESSION);
|
|
emitNode(p, n, &count);
|
|
emitOp(p, n, T_END_EXPRESSION);
|
|
emitOp(p, n, T_END_EXPRESSION);
|
|
emitOp(p, n, T_END_STATEMENT);
|
|
|
|
//symbolVal:=get_array(a, symbolKey); // works for both assoc and normal arrays
|
|
emitOp(p, n, T_START_STATEMENT);
|
|
emitNode(p, n, &symbolVal);
|
|
emitOp(p, n, T_ASSIGN);
|
|
emitOp(p, n, T_START_EXPRESSION);
|
|
emitOp(p, n, T_TS_GET_ARRAY);
|
|
emitOp(p, n, T_START_EXPRESSION);
|
|
appendNodeList(n, &arrayVar);
|
|
emitOp(p, n, T_END_EXPRESSION);
|
|
emitOp(p, n, T_START_EXPRESSION);
|
|
emitNode(p, n, &symbolKey);
|
|
emitOp(p, n, T_END_EXPRESSION);
|
|
emitOp(p, n, T_END_EXPRESSION);
|
|
emitOp(p, n, T_END_STATEMENT);
|
|
|
|
//The actual loop contents
|
|
loopNesting++;
|
|
parseStatement(p);
|
|
loopNesting--;
|
|
|
|
// special marker for code generator
|
|
emitOp(p, n, T_START_STATEMENT);
|
|
emitOp(p, n, T_LOOP_END);
|
|
emitOp(p, n, T_END_STATEMENT);
|
|
//count+=1;
|
|
emitOp(p, n, T_START_STATEMENT);
|
|
emitNode(p, n, &count);
|
|
emitOp(p, n, T_ASSIGN_ADD);
|
|
emitOp(p, n, T_START_EXPRESSION);
|
|
emitInt(p, n, 1);
|
|
emitOp(p, n, T_END_EXPRESSION);
|
|
emitOp(p, n, T_END_STATEMENT);
|
|
|
|
//end
|
|
emitOp(p, n, T_END);
|
|
emitOp(p, n, T_END_STATEMENT);
|
|
emitOp(p, n, T_END_STATEMENT);
|
|
|
|
free(symbolVal.stringData);
|
|
free(symbolKey.stringData);
|
|
free(len.stringData);
|
|
free(count.stringData);
|
|
free(tmpN.nodes);
|
|
free(arrayVar.nodes);
|
|
}
|
|
|
|
void parseSwitch(Procedure *p, NodeList *n) {
|
|
LexData symbol;
|
|
int cases=0;
|
|
if(expectToken(T_SYMBOL)==-1) {
|
|
GenTmpVar(p, &symbol);
|
|
emitNode(p, n, &symbol);
|
|
emitOp(p, n, T_ASSIGN);
|
|
parseExpression(p, n);
|
|
emitOp(p, n, T_END_STATEMENT);
|
|
emitOp(p, n, T_START_STATEMENT);
|
|
} else {
|
|
CloneLexData(&symbol, &lexData);
|
|
}
|
|
if(expectToken(T_BEGIN)==-1) parseError("Expected begin");
|
|
while(expectToken(T_CASE)!=-1) {
|
|
if(cases) {
|
|
emitOp(p, n, T_ELSE);
|
|
emitOp(p, n, T_START_STATEMENT);
|
|
emitOp(p, n, T_BEGIN);
|
|
emitOp(p, n, T_START_STATEMENT);
|
|
}
|
|
emitOp(p, n, T_IF);
|
|
emitOp(p, n, T_START_EXPRESSION);
|
|
emitNode(p, n, &symbol);
|
|
parseExpression(p, n);
|
|
emitOp(p, n, T_EQUAL);
|
|
emitOp(p, n, T_END_EXPRESSION);
|
|
emitOp(p, n, T_THEN);
|
|
emitOp(p, n, T_START_STATEMENT);
|
|
emitOp(p, n, T_BEGIN);
|
|
if(expectToken(':')==-1) parseError("Expected ':'");
|
|
while(expectToken(T_EOF)==-1&&expectToken(T_CASE)==-1&&expectToken(T_DEFAULT)==-1&&expectToken(T_END)==-1) parseStatement(p);
|
|
ungetToken();
|
|
emitOp(p, n, T_END);
|
|
emitOp(p, n, T_END_STATEMENT);
|
|
cases++;
|
|
}
|
|
if(cases&&expectToken(T_DEFAULT)!=-1) {
|
|
if(expectToken(':')==-1) parseError("Expected ':'");
|
|
emitOp(p, n, T_ELSE);
|
|
emitOp(p, n, T_START_STATEMENT);
|
|
emitOp(p, n, T_BEGIN);
|
|
while(expectToken(T_EOF)==-1&&expectToken(T_CASE)==-1&&expectToken(T_DEFAULT)==-1&&expectToken(T_END)==-1) parseStatement(p);
|
|
ungetToken();
|
|
emitOp(p, n, T_END);
|
|
emitOp(p, n, T_END_STATEMENT);
|
|
}
|
|
if(!cases) parseSemanticError("switch statement with no cases");
|
|
while(--cases) {
|
|
emitOp(p, n, T_END_STATEMENT);
|
|
emitOp(p, n, T_END);
|
|
emitOp(p, n, T_END_STATEMENT);
|
|
}
|
|
if(expectToken(T_END)==-1) parseError("Expected end");
|
|
}
|
|
|
|
static void emitIntConstIntExpr(Procedure *p, NodeList *n, int i) {
|
|
emitOp(p, n, T_START_EXPRESSION);
|
|
emitInt(p, n, i);
|
|
emitOp(p, n, T_END_EXPRESSION);
|
|
}
|
|
|
|
static void emitSubExpressionTerminator(Procedure *p, NodeList *n) {
|
|
// Special temp_array call that will not actually create any array, but pop the internal expression stack for nested expressions to work properly
|
|
emitOp(p, n, T_TS_TEMP_ARRAY);
|
|
emitIntConstIntExpr(p, n, 0);
|
|
emitIntConstIntExpr(p, n, ARRAYFLAG_EXPR_POP);
|
|
emitOp(p, n, '+');
|
|
}
|
|
|
|
void parseAssocArrayExpression(Procedure *p, NodeList *n) {
|
|
arrayExpressionNesting++;
|
|
emitOp(p, n, T_TS_TEMP_ARRAY);
|
|
emitIntConstIntExpr(p, n, -1);
|
|
emitIntConstIntExpr(p, n, arrayExpressionNesting > 1 ? ARRAYFLAG_EXPR_PUSH : 0);
|
|
if (lex() != '}') {
|
|
ungetToken();
|
|
emitOp(p, n, T_TS_STACK_ARRAY);
|
|
parseExpression(p, n);
|
|
if (expectToken(':') == -1) parseError("Expected ':'");
|
|
parseExpression(p, n);
|
|
emitOp(p, n, '+');
|
|
while (lex() == ',') {
|
|
emitOp(p, n, T_TS_STACK_ARRAY);
|
|
parseExpression(p, n);
|
|
if (expectToken(':') == -1) parseError("Expected ':'");
|
|
parseExpression(p, n);
|
|
emitOp(p, n, '+');
|
|
}
|
|
ungetToken();
|
|
if (lex() != '}') {
|
|
parseError("Mismatched '{}'");
|
|
}
|
|
}
|
|
if (arrayExpressionNesting > 1) {
|
|
emitSubExpressionTerminator(p, n);
|
|
}
|
|
arrayExpressionNesting--;
|
|
}
|
|
|
|
void parseArrayExpression(Procedure *p, NodeList *n) {
|
|
int i;
|
|
arrayExpressionNesting++;
|
|
|
|
emitOp(p, n, T_TS_TEMP_ARRAY);
|
|
emitIntConstIntExpr(p, n, 0); // size
|
|
emitIntConstIntExpr(p, n, arrayExpressionNesting > 1 ? ARRAYFLAG_EXPR_PUSH : 0);
|
|
|
|
if (lex() != ']') {
|
|
ungetToken();
|
|
emitOp(p, n, T_TS_STACK_ARRAY);
|
|
emitIntConstIntExpr(p, n, 0); // first index
|
|
parseExpression(p, n);
|
|
emitOp(p, n, '+');
|
|
i = 1;
|
|
while (lex() == ',') {
|
|
emitOp(p, n, T_TS_STACK_ARRAY);
|
|
emitIntConstIntExpr(p, n, i); // index
|
|
parseExpression(p, n);
|
|
emitOp(p, n, '+');
|
|
i++;
|
|
}
|
|
ungetToken();
|
|
if (lex() != ']') {
|
|
parseError("Mismatched '[]'");
|
|
}
|
|
}
|
|
if (arrayExpressionNesting > 1) {
|
|
emitSubExpressionTerminator(p, n);
|
|
}
|
|
arrayExpressionNesting--;
|
|
} |