|
|
|
@ -24,24 +24,25 @@
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
#include <cctype>
|
|
|
|
|
#include <cstdlib>
|
|
|
|
|
#include <iostream>
|
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
|
|
void Parser::addString(const std::string& str)
|
|
|
|
|
{
|
|
|
|
|
if (!str.empty())
|
|
|
|
|
std::copy(str.cbegin(), str.cend(), std::back_inserter(text));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Parser::consumeWhitespace()
|
|
|
|
|
void Parser::consumeWhitespace() noexcept
|
|
|
|
|
{
|
|
|
|
|
while (isspace(text.front()))
|
|
|
|
|
text.pop_front();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::optional<std::string> Parser::consumeIdentifier()
|
|
|
|
|
std::optional<std::string> Parser::consumeIdentifier() noexcept
|
|
|
|
|
{
|
|
|
|
|
std::string ret;
|
|
|
|
|
|
|
|
|
|
// TODO Accept all valid identifiers according to R7RS-small.
|
|
|
|
|
if (isalpha(text.front())) {
|
|
|
|
|
do {
|
|
|
|
|
ret += text.front();
|
|
|
|
@ -66,32 +67,35 @@ std::optional<std::variant<int, double>> Parser::consumeLiteralNumber()
|
|
|
|
|
|
|
|
|
|
if (ret.empty())
|
|
|
|
|
return {};
|
|
|
|
|
else if (ret.find('.') == std::string::npos)
|
|
|
|
|
return (int)strtol(ret.c_str(), nullptr, 0);
|
|
|
|
|
else
|
|
|
|
|
return strtod(ret.c_str(), nullptr);
|
|
|
|
|
|
|
|
|
|
if (ret.find('.') == std::string::npos) {
|
|
|
|
|
int r = strtol(ret.c_str(), nullptr, 0);
|
|
|
|
|
// TODO Error check
|
|
|
|
|
return r;
|
|
|
|
|
} else {
|
|
|
|
|
auto r = strtod(ret.c_str(), nullptr);
|
|
|
|
|
// TODO Error check
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AST::Node *Parser::parse(CompilerState& state)
|
|
|
|
|
std::deque<AST::Node *> Parser::parse()
|
|
|
|
|
{
|
|
|
|
|
AST::Node *ret = nullptr;
|
|
|
|
|
std::deque<AST::Node *> ret;
|
|
|
|
|
|
|
|
|
|
errors.clear();
|
|
|
|
|
while (!text.empty()) {
|
|
|
|
|
consumeWhitespace();
|
|
|
|
|
|
|
|
|
|
// At the top-level, there will only be procedure calls.
|
|
|
|
|
ret = parseProcedureCall();
|
|
|
|
|
if (lastError != None)
|
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::cout << (ret ? ret->desc() : "nullptr") << std::endl;
|
|
|
|
|
|
|
|
|
|
if (ret)
|
|
|
|
|
ret->codegen(state);
|
|
|
|
|
auto node = parseProcedureCall();
|
|
|
|
|
if (errors.empty() && node) {
|
|
|
|
|
ret.push_back(node);
|
|
|
|
|
} else {
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lastError = None;
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -110,6 +114,7 @@ AST::Node *Parser::parseExpression()
|
|
|
|
|
return lit;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
errors.push_back(InvalidExpression);
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -117,7 +122,7 @@ AST::Node *Parser::parseProcedureCall()
|
|
|
|
|
{
|
|
|
|
|
// Consume the opening parenthesis.
|
|
|
|
|
if (text.front() != '(') {
|
|
|
|
|
lastError = ExpectedProcedure;
|
|
|
|
|
errors.push_back(ExpectedProcedureCallOpen);
|
|
|
|
|
return nullptr;
|
|
|
|
|
} else {
|
|
|
|
|
text.pop_front();
|
|
|
|
@ -125,11 +130,10 @@ AST::Node *Parser::parseProcedureCall()
|
|
|
|
|
|
|
|
|
|
// Consume the identifier string.
|
|
|
|
|
auto ident = parseExpression();
|
|
|
|
|
if (ident == nullptr) {
|
|
|
|
|
lastError = InvalidOperator;
|
|
|
|
|
if (ident == nullptr)
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check for special procedure calls.
|
|
|
|
|
if (auto id = dynamic_cast<AST::Identifier *>(ident); id) {
|
|
|
|
|
if (id->name == "lambda")
|
|
|
|
|
return parseLambdaExpression();
|
|
|
|
@ -141,13 +145,16 @@ AST::Node *Parser::parseProcedureCall()
|
|
|
|
|
return parseAssignment();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This is a regular procedure call.
|
|
|
|
|
// Build the argument list:
|
|
|
|
|
|
|
|
|
|
std::vector<AST::Node *> args;
|
|
|
|
|
|
|
|
|
|
consumeWhitespace();
|
|
|
|
|
while (text.front() != ')') {
|
|
|
|
|
auto node = parseExpression();
|
|
|
|
|
if (node == nullptr) {
|
|
|
|
|
lastError = InvalidOperand;
|
|
|
|
|
errors.push_back(InvalidOperand);
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -164,7 +171,7 @@ AST::Node *Parser::parseProcedureCall()
|
|
|
|
|
|
|
|
|
|
return pc;
|
|
|
|
|
} else {
|
|
|
|
|
lastError = ExpectedProcedureCallClose;
|
|
|
|
|
errors.push_back(ExpectedProcedureCallClose);
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -173,18 +180,24 @@ AST::Node *Parser::parseConditional()
|
|
|
|
|
{
|
|
|
|
|
consumeWhitespace();
|
|
|
|
|
auto cond = parseExpression();
|
|
|
|
|
if (cond == nullptr)
|
|
|
|
|
if (cond == nullptr) {
|
|
|
|
|
errors.push_back(InvalidCondition);
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
consumeWhitespace();
|
|
|
|
|
auto ift = parseExpression();
|
|
|
|
|
if (ift == nullptr)
|
|
|
|
|
if (ift == nullptr) {
|
|
|
|
|
errors.push_back(InvalidThenBranch);
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
consumeWhitespace();
|
|
|
|
|
auto iff = parseExpression();
|
|
|
|
|
if (iff == nullptr)
|
|
|
|
|
if (iff == nullptr) {
|
|
|
|
|
errors.push_back(InvalidThenBranch);
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
consumeWhitespace();
|
|
|
|
|
if (text.front() == ')') {
|
|
|
|
@ -195,10 +208,11 @@ AST::Node *Parser::parseConditional()
|
|
|
|
|
node->iftrue = ift;
|
|
|
|
|
node->iffalse = iff;
|
|
|
|
|
return node;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
errors.push_back(ExpectedProcedureCallClose);
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AST::Node *Parser::parseDefinition()
|
|
|
|
|
{
|
|
|
|
@ -221,8 +235,14 @@ AST::Node *Parser::parseDefinition()
|
|
|
|
|
def->ident = id;
|
|
|
|
|
def->value = val;
|
|
|
|
|
return def;
|
|
|
|
|
} else {
|
|
|
|
|
errors.push_back(ExpectedProcedureCallClose);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
errors.push_back(InvalidInitializer);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
errors.push_back(ExpectedIdentifier);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
@ -249,8 +269,14 @@ AST::Node *Parser::parseAssignment()
|
|
|
|
|
def->ident = id;
|
|
|
|
|
def->value = val;
|
|
|
|
|
return def;
|
|
|
|
|
} else {
|
|
|
|
|
errors.push_back(ExpectedProcedureCallClose);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
errors.push_back(InvalidAssignValue);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
errors.push_back(ExpectedIdentifier);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
@ -258,15 +284,17 @@ AST::Node *Parser::parseAssignment()
|
|
|
|
|
|
|
|
|
|
AST::Node *Parser::parseLambdaExpression()
|
|
|
|
|
{
|
|
|
|
|
// First get argument list
|
|
|
|
|
// Consume beginning of argument list.
|
|
|
|
|
consumeWhitespace();
|
|
|
|
|
if (text.front() != '(') {
|
|
|
|
|
lastError = ExpectedArgumentList;
|
|
|
|
|
errors.push_back(ExpectedArgumentList);
|
|
|
|
|
return nullptr;
|
|
|
|
|
} else {
|
|
|
|
|
text.pop_front();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Consume argument list:
|
|
|
|
|
|
|
|
|
|
std::vector<AST::Identifier *> args;
|
|
|
|
|
|
|
|
|
|
while (text.front() != ')') {
|
|
|
|
@ -276,22 +304,28 @@ AST::Node *Parser::parseLambdaExpression()
|
|
|
|
|
ident->name = *arg;
|
|
|
|
|
args.push_back(ident);
|
|
|
|
|
} else {
|
|
|
|
|
lastError = InvalidOperand;
|
|
|
|
|
errors.push_back(InvalidArgumentName);
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
consumeWhitespace();
|
|
|
|
|
}
|
|
|
|
|
text.pop_front(); // consume arg list ')'
|
|
|
|
|
|
|
|
|
|
// Consume arg list closing ')' that must be there.
|
|
|
|
|
text.pop_front();
|
|
|
|
|
|
|
|
|
|
// Consume lambda body:
|
|
|
|
|
|
|
|
|
|
std::vector<AST::Node *> body;
|
|
|
|
|
|
|
|
|
|
// Next, consume function body.
|
|
|
|
|
consumeWhitespace();
|
|
|
|
|
while (text.front() != ')') {
|
|
|
|
|
auto exp = parseExpression();
|
|
|
|
|
//if (exp == nullptr) // TODO commands/definitions are okay
|
|
|
|
|
// return nullptr;
|
|
|
|
|
|
|
|
|
|
if (!errors.empty()) {
|
|
|
|
|
errors.push_back(InvalidLambdaBody);
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
body.push_back(exp);
|
|
|
|
|
consumeWhitespace();
|
|
|
|
@ -306,8 +340,64 @@ AST::Node *Parser::parseLambdaExpression()
|
|
|
|
|
|
|
|
|
|
return le;
|
|
|
|
|
} else {
|
|
|
|
|
lastError = ExpectedProcedureCallClose;
|
|
|
|
|
errors.push_back(ExpectedProcedureCallClose);
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string Parser::describeErrors() noexcept
|
|
|
|
|
{
|
|
|
|
|
std::string ret;
|
|
|
|
|
|
|
|
|
|
for (auto& err : errors) {
|
|
|
|
|
switch (err) {
|
|
|
|
|
case ExpectedProcedureCallOpen:
|
|
|
|
|
ret += "Expected opening \'(\' for procedure call.\n";
|
|
|
|
|
break;
|
|
|
|
|
case ExpectedIdentifier:
|
|
|
|
|
ret += "Expected a valid identifier.\n";
|
|
|
|
|
break;
|
|
|
|
|
case ExpectedProcedureCallClose:
|
|
|
|
|
ret += "Expected closing \')\' for procedure call.\n";
|
|
|
|
|
break;
|
|
|
|
|
case ExpectedArgumentList:
|
|
|
|
|
ret += "Expected beginning of argument list.\n";
|
|
|
|
|
break;
|
|
|
|
|
case UnknownIdentifier:
|
|
|
|
|
ret += "Given identifier is not valid.\n";
|
|
|
|
|
break;
|
|
|
|
|
case InvalidExpression:
|
|
|
|
|
ret += "Expected a valid expression.\n";
|
|
|
|
|
break;
|
|
|
|
|
case InvalidOperand:
|
|
|
|
|
ret += "Given invalid argument or operand.\n";
|
|
|
|
|
break;
|
|
|
|
|
case InvalidCondition:
|
|
|
|
|
ret += "Given invalid condition for conditional statement.\n";
|
|
|
|
|
break;
|
|
|
|
|
case InvalidThenBranch:
|
|
|
|
|
ret += "Given invalid \"then\" branch for conditional statement.\n";
|
|
|
|
|
break;
|
|
|
|
|
case InvalidElseBranch:
|
|
|
|
|
ret += "Given invalid \"else\" branch for conditional statement.\n";
|
|
|
|
|
break;
|
|
|
|
|
case InvalidInitializer:
|
|
|
|
|
ret += "Given invalid initializer for a declaration.\n";
|
|
|
|
|
break;
|
|
|
|
|
case InvalidAssignValue:
|
|
|
|
|
ret += "Given invalid value for an assignment.\n";
|
|
|
|
|
break;
|
|
|
|
|
case InvalidArgumentName:
|
|
|
|
|
ret += "Given invalid name for an argument.\n";
|
|
|
|
|
break;
|
|
|
|
|
case InvalidLambdaBody:
|
|
|
|
|
ret += "Lambda body is invalid.\n";
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|