static bool parseTypeIdentifier(MemoryStack* stack, LexerCarriage* carriage, Array<SyntaxError>* errors, ASTNode* result) { if (carriage->topToken.type == TOK_REF) { parseNextToken(carriage); result->nodeType = AST_TYPE_IDENTIFIER; result->typeIdentifier.isReference = true; result->typeIdentifier.name = carriage->topToken.identifierValue; // TODO: add error checking parseNextToken(carriage); return true; } else if (carriage->topToken.type == TOK_IDENTIFIER) { result->nodeType = AST_TYPE_IDENTIFIER; result->typeIdentifier.isReference = false; result->typeIdentifier.name = carriage->topToken.identifierValue; parseNextToken(carriage); return true; } else return false; }
static bool parseFunctionCall(MemoryStack* stack, LexerCarriage* carriage, Array<SyntaxError>* errors, ASTNode* result) { LexerCarriage tmpCarriage = *carriage; if (tmpCarriage.topToken.type == TOK_IDENTIFIER) { Token identifier = tmpCarriage.topToken; parseNextToken(&tmpCarriage); if (tmpCarriage.topToken.type == TOK_OPEN_BRACKET) { parseNextToken(&tmpCarriage); result->nodeType = AST_FUNCTION_CALL; result->functionCall.lineNumber = carriage->currentLineNumber; result->functionCall.identifier = identifier.identifierValue; result->functionCall.arguments = { }; if (tmpCarriage.topToken.type != TOK_CLOSE_BRACKET) { ASTNode argument; do { if (parseExpression(stack, &tmpCarriage, errors, &argument)) { *pushElement(&result->functionCall.arguments, stack) = argument; if (tmpCarriage.topToken.type == TOK_COMMA) parseNextToken(&tmpCarriage); else break; } else { pushBack(errors, SyntaxError{ SET_EXPRESSION_EXPECTED }); break; } } while (true); } expectAndEat(&tmpCarriage, TOK_CLOSE_BRACKET, errors); *carriage = tmpCarriage; return true; } } return false; }
static bool parseLValueExpression(MemoryStack* stack, LexerCarriage* carriage, Array<SyntaxError>* errors, ASTNode left, ASTNode* result) { if (carriage->topToken.type == TOK_DOT) { parseNextToken(carriage); ASTNode right; if (parseIdentifierExpression(stack, carriage, errors, &right)) { result->nodeType = AST_EXPRESSION_DOT; result->binary.left = pushMemory<ASTNode>(stack); result->binary.right = pushMemory<ASTNode>(stack); *result->binary.left = left; *result->binary.right = right; parseLValueExpression(stack, carriage, errors, *result, result); return true; } return false; } else { *result = left; return true; } }
static bool parseAssignment(MemoryStack* stack, LexerCarriage* carriage, Array<SyntaxError>* errors, ASTNode* result) { LexerCarriage tmpCarriage = *carriage; ASTNode lValue; if (parseLValueExpression(stack, &tmpCarriage, errors, &lValue)) { if (tmpCarriage.topToken.type == TOK_ASSIGN) { parseNextToken(&tmpCarriage); result->nodeType = AST_STATEMENT_ASSIGNMENT; result->assignment.lineNumber = tmpCarriage.currentLineNumber; result->assignment.lValue = pushMemory<ASTNode>(stack); result->assignment.expression = pushMemory<ASTNode>(stack); *result->assignment.lValue = lValue; expectAndEatExpression(stack, &tmpCarriage, errors, result->assignment.expression); *carriage = tmpCarriage; return true; } } return false; }
static bool parseNotExpression(MemoryStack* stack, LexerCarriage* carriage, Array<SyntaxError>* errors, ASTNode* result) { if (carriage->topToken.type == TOK_NOT) { parseNextToken(carriage); result->nodeType = AST_FUNCTION_CALL; result->functionCall.identifier = makeSlice("opNot"); result->functionCall.arguments = {}; ASTNode node; if (parseAddSubExpression(stack, carriage, errors, &node)) { *pushElement(&result->functionCall.arguments, stack) = node; return true; } else return false; } else { return parseAddSubExpression(stack, carriage, errors, result); } }
static bool parseAndOrExpression(MemoryStack* stack, LexerCarriage* carriage, Array<SyntaxError>* errors, ASTNode left, ASTNode* result) { if (carriage->topToken.type == TOK_AND) { parseNextToken(carriage); ASTNode right; if (parseCompareExpression(stack, carriage, errors, &right)) { makeFunctionCallNode(result, stack, "opAnd", left, right); parseAndOrExpression(stack, carriage, errors, *result, result); return true; } else { pushBack(errors, SyntaxError{ SET_EXPRESSION_EXPECTED, carriage->currentLineNumber }); return false; } } else if (carriage->topToken.type == TOK_OR) { parseNextToken(carriage); ASTNode right; if (parseCompareExpression(stack, carriage, errors, &right)) { makeFunctionCallNode(result, stack, "opOr", left, right); parseAndOrExpression(stack, carriage, errors, *result, result); return true; } else { pushBack(errors, SyntaxError{ SET_EXPRESSION_EXPECTED, carriage->currentLineNumber }); return false; } } else { *result = left; return true; } }
static bool parseVariableDefinition(MemoryStack* stack, LexerCarriage* carriage, Array<SyntaxError>* errors, ASTNode* result) { LexerCarriage tmpCarriage = *carriage; if (tmpCarriage.topToken.type == TOK_IDENTIFIER) { Token identifier = tmpCarriage.topToken; parseNextToken(&tmpCarriage); if (tmpCarriage.topToken.type == TOK_DOUBLE_DOT) { parseNextToken(&tmpCarriage); ASTNode typeIdentifier; if (parseTypeIdentifier(stack, &tmpCarriage, errors, &typeIdentifier)) { result->nodeType = AST_STATEMENT_VARIABLE_DECLARATION; result->variableDeclaration.lineNumber = carriage->currentLineNumber; result->variableDeclaration.identifier = identifier.identifierValue; result->variableDeclaration.typeIdentifier = pushMemory<ASTNode>(stack); *result->variableDeclaration.typeIdentifier = typeIdentifier; if (tmpCarriage.topToken.type == TOK_ASSIGN) { parseNextToken(&tmpCarriage); result->variableDeclaration.expression = pushMemory<ASTNode>(stack); expectAndEatExpression(stack, &tmpCarriage, errors, result->variableDeclaration.expression); } else result->variableDeclaration.expression = nullptr; *carriage = tmpCarriage; return true; } } } return false; };
LexerCarriage initCarriage(char* text) { LexerCarriage result; result.lexingText = makeSlice(text); result.posInText = 0; result.currentLineNumber = 1; parseNextToken(&result); return result; }
static bool parseMulDivExpression(MemoryStack* stack, LexerCarriage* carriage, Array<SyntaxError>* errors, ASTNode left, ASTNode* result) { if (carriage->topToken.type == TOK_MULTIPLY) { parseNextToken(carriage); ASTNode right; if (parseValueExpression(stack, carriage, errors, &right)) { makeFunctionCallNode(result, stack, "opMul", left, right); parseMulDivExpression(stack, carriage, errors, *result, result); return true; } else pushBack(errors, SyntaxError{ SET_EXPRESSION_EXPECTED, carriage->currentLineNumber }); } else if (carriage->topToken.type == TOK_DIVIDE) { parseNextToken(carriage); ASTNode right; if (parseValueExpression(stack, carriage, errors, &right)) { makeFunctionCallNode(result, stack, "opDiv", left, right); parseMulDivExpression(stack, carriage, errors, *result, result); return true; } else pushBack(errors, SyntaxError{ SET_EXPRESSION_EXPECTED, carriage->currentLineNumber }); } else { *result = left; return true; } return false; }
static void expectAndEat(LexerCarriage* carriage, TokenType expect, Array<SyntaxError>* errors) { if (carriage->topToken.type != expect) { SyntaxError error = SyntaxError{ SET_UNEXPECTED_TOKEN, carriage->currentLineNumber }; error.unexpectedToken.token = carriage->topToken; error.unexpectedToken.expecting = expect; pushBack(errors, error); } else parseNextToken(carriage); }
static bool parseIdentifierExpression(MemoryStack* stack, LexerCarriage* carriage, Array<SyntaxError>* errors, ASTNode* result) { if (carriage->topToken.type == TOK_IDENTIFIER) { result->nodeType = AST_EXPRESSION_IDENTIFIER; result->identifier.identifier = carriage->topToken.identifierValue; result->identifier.lineNumber = carriage->currentLineNumber; parseNextToken(carriage); return true; } return false; }
// TODO: this is horrible! (and I think is wrong) static void skipComment(LexerCarriage* carriage) { if (carriage->topToken.type == TOK_ONE_LINE_COMMENT) { while (carriage->posInText < carriage->lexingText.length) { ++carriage->posInText; if (carriage->lexingText.pointer[carriage->posInText] == '\n') { break; } } parseNextToken(carriage); } }
static bool parseValueExpression(MemoryStack* stack, LexerCarriage* carriage, Array<SyntaxError>* errors, ASTNode* result) { if (parseFunctionCall(stack, carriage, errors, result)) return true; else if (parseLValueExpression(stack, carriage, errors, result)) return true; else if (carriage->topToken.type == TOK_NUMBER_CONSTANT) { result->nodeType = AST_EXPRESSION_CONSTANT; result->constantValue = carriage->topToken.constant.value; parseNextToken(carriage); return true; } else return false; }
uint16 Script::readLineToken(bool errorOnEOF) { char buf[200]; char *line = readLine(buf, 200); if (!line) { if (errorOnEOF) error("unexpected end of file while parsing"); else return 0; } clearTokens(); while (*line && _numTokens < MAX_TOKENS) { line = parseNextToken(line, _tokens[_numTokens], MAX_TOKEN_LEN, " "); line = Common::ltrim(line); _numTokens++; } return _numTokens; }
static bool parseStatement(MemoryStack* stack, LexerCarriage* carriage, Array<SyntaxError>* errors, ASTNode* result) { if (parseVariableDefinition(stack, carriage, errors, result)) return true; if (parseFunctionCall(stack, carriage, errors, result)) return true; if (parseAssignment(stack, carriage, errors, result)) return true; if (carriage->topToken.type == TOK_IDENTIFIER) { Token identifier = carriage->topToken; parseNextToken(carriage); if (carriage->topToken.type == TOK_DOUBLE_DOT) { parseNextToken(carriage); if (carriage->topToken.type == TOK_OPEN_BRACKET) // function definition { parseNextToken(carriage); result->nodeType = AST_STATEMENT_FUNCTION_DEFINITION; result->functionDefinition.lineNumber = carriage->currentLineNumber; result->functionDefinition.identifier = identifier.identifierValue; ASTNode arg; LinkedList<ASTNode> args = {}; if (carriage->topToken.type != TOK_CLOSE_BRACKET) { while (true) { if (parseVariableDefinition(stack, carriage, errors, &arg)) { *pushElement(&args, stack) = arg; if (carriage->topToken.type != TOK_COMMA) break; else parseNextToken(carriage); // pop , } else { pushBack(errors, SyntaxError{ SET_EXPRESSION_EXPECTED }); break; } }; } expectAndEat(carriage, TOK_CLOSE_BRACKET, errors); result->functionDefinition.arguments = args; if (carriage->topToken.type != TOK_VOID) { result->functionDefinition.returnType = pushMemory<ASTNode>(stack); if (!parseTypeIdentifier(stack, carriage, errors, result->functionDefinition.returnType)) { // TODO: change this SyntaxError error = SyntaxError{ SET_UNEXPECTED_TOKEN }; error.unexpectedToken.token = carriage->topToken; error.unexpectedToken.expecting = TOK_IDENTIFIER; pushBack(errors, error); } } else { parseNextToken(carriage); result->functionDefinition.returnType = nullptr; } result->functionDefinition.body = nullptr; if (carriage->topToken.type == TOK_ASSIGN) { parseNextToken(carriage); result->functionDefinition.body = pushMemory<ASTNode>(stack); expectAndEatStatement(stack, carriage, errors, result->functionDefinition.body); } return true; } else if (carriage->topToken.type == TOK_STRUCT) { parseNextToken(carriage); expectAndEat(carriage, TOK_ASSIGN, errors); int bracesOpenedAt = carriage->currentLineNumber; expectAndEat(carriage, TOK_OPEN_BRACES, errors); result->nodeType = AST_STATEMENT_TYPE_DEFINITION; result->typeDefinition.lineNumber = carriage->currentLineNumber; result->typeDefinition.identifier = identifier.identifierValue; result->typeDefinition.definitions = {}; ASTNode definition; do { if (parseVariableDefinition(stack, carriage, errors, &definition)) *pushElement(&result->typeDefinition.definitions, stack) = definition; else break; } while (true); if (carriage->topToken.type == TOK_CLOSE_BRACES) parseNextToken(carriage); else { SyntaxError error = { SET_UNCLOSED_BRACKETS, bracesOpenedAt }; error.unclosedBrackets.closedAt = carriage->currentLineNumber; error.unclosedBrackets.token = carriage->topToken; pushBack(errors, error); } return true; } else { // TODO: error } } else { // TODO: error } } else if (carriage->topToken.type == TOK_OPEN_BRACES) { int openedAt = carriage->currentLineNumber; parseNextToken(carriage); result->nodeType = AST_STATEMENTS_BLOCK; result->statementsBlock.statements = { }; parseStatements(stack, carriage, errors, &result->statementsBlock.statements); if (carriage->topToken.type == TOK_CLOSE_BRACES) parseNextToken(carriage); else { SyntaxError error = SyntaxError{ SET_UNCLOSED_BRACKETS, openedAt }; error.unclosedBrackets.closedAt = carriage->currentLineNumber; error.unclosedBrackets.token = carriage->topToken; pushBack(errors, error); } return true; } else if (carriage->topToken.type == TOK_IF) { parseNextToken(carriage); result->nodeType = AST_STATEMENT_IF; result->ifStatement.condition = pushMemory<ASTNode>(stack); result->ifStatement.ifCase = pushMemory<ASTNode>(stack); expectAndEatExpression(stack, carriage, errors, result->ifStatement.condition); expectAndEatStatement(stack, carriage, errors, result->ifStatement.ifCase); if (carriage->topToken.type == TOK_ELSE) { parseNextToken(carriage); result->ifStatement.elseCase = pushMemory<ASTNode>(stack); expectAndEatStatement(stack, carriage, errors, result->ifStatement.elseCase); } else result->ifStatement.elseCase = nullptr; return true; } else if (carriage->topToken.type == TOK_WHILE) { parseNextToken(carriage); result->nodeType = AST_STATEMENT_WHILE; result->whileStatement.condition = pushMemory<ASTNode>(stack); result->whileStatement.body = pushMemory<ASTNode>(stack); expectAndEatExpression(stack, carriage, errors, result->whileStatement.condition); expectAndEatStatement(stack, carriage, errors, result->whileStatement.body); return true; } return false; }
// TODO: add chaining? static bool parseCompareExpression(MemoryStack* stack, LexerCarriage* carriage, Array<SyntaxError>* errors, ASTNode left, ASTNode* result) { if (carriage->topToken.type == TOK_EQUALS) { parseNextToken(carriage); ASTNode right; if (parseNotExpression(stack, carriage, errors, &right)) { makeFunctionCallNode(result, stack, "opEquals", left, right); parseCompareExpression(stack, carriage, errors, *result, result); return true; } else pushBack(errors, SyntaxError{ SET_EXPRESSION_EXPECTED, carriage->currentLineNumber }); } else if (carriage->topToken.type == TOK_LESS) { parseNextToken(carriage); ASTNode right; if (parseNotExpression(stack, carriage, errors, &right)) { makeFunctionCallNode(result, stack, "opLess", left, right); parseCompareExpression(stack, carriage, errors, *result, result); return true; } else pushBack(errors, SyntaxError{ SET_EXPRESSION_EXPECTED, carriage->currentLineNumber }); } else if (carriage->topToken.type == TOK_GREATER) { parseNextToken(carriage); ASTNode right; if (parseNotExpression(stack, carriage, errors, &right)) { makeFunctionCallNode(result, stack, "opGreater", left, right); parseCompareExpression(stack, carriage, errors, *result, result); return true; } else pushBack(errors, SyntaxError{ SET_EXPRESSION_EXPECTED, carriage->currentLineNumber }); } else if (carriage->topToken.type == TOK_EQUALS_OR_LESS) { parseNextToken(carriage); ASTNode right; if (parseNotExpression(stack, carriage, errors, &right)) { makeFunctionCallNode(result, stack, "opEqualsOrLess", left, right); parseCompareExpression(stack, carriage, errors, *result, result); return true; } else pushBack(errors, SyntaxError{ SET_EXPRESSION_EXPECTED, carriage->currentLineNumber }); } else if (carriage->topToken.type == TOK_EQUALS_OR_GREATER) { parseNextToken(carriage); ASTNode right; if (parseNotExpression(stack, carriage, errors, &right)) { makeFunctionCallNode(result, stack, "opEqualsOrGreater", left, right); parseCompareExpression(stack, carriage, errors, *result, result); return true; } else pushBack(errors, SyntaxError{ SET_EXPRESSION_EXPECTED, carriage->currentLineNumber }); } else { *result = left; return true; } return false; }