Files
sslc/parseext.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--;
}