diff --git a/examples/subtraction.lang b/examples/subtraction.lang new file mode 100644 index 0000000..727bbd6 --- /dev/null +++ b/examples/subtraction.lang @@ -0,0 +1,6 @@ +uint8 a = 6 - 1; +uint8 b = a - 1; + +uint8 c = a - b; + +return c; \ No newline at end of file diff --git a/src/generation/builder/builder.hpp b/src/generation/builder/builder.hpp index 0e78906..fb80590 100644 --- a/src/generation/builder/builder.hpp +++ b/src/generation/builder/builder.hpp @@ -77,6 +77,10 @@ class Builder { return this->irBuilder.CreateAdd(lhs, rhs, name); }; + llvm::Value* subtract(llvm::Value* lhs, llvm::Value* rhs, std::string name) { + return this->irBuilder.CreateSub(lhs, rhs, name); + }; + llvm::Value* zext(llvm::Value* in, llvm::Type* outType) { return this->irBuilder.CreateZExt(in, outType); }; diff --git a/src/generation/generator.hpp b/src/generation/generator.hpp index 75c95d8..b1536b7 100644 --- a/src/generation/generator.hpp +++ b/src/generation/generator.hpp @@ -15,6 +15,7 @@ #include "syntax_analyser/statement/print/print.hpp" #include "syntax_analyser/statement/return/return.hpp" #include "syntax_analyser/statement/statement.hpp" +#include "syntax_analyser/statement/subtraction/subtraction.hpp" #include "syntax_analyser/statement/value/identifier/identifier.hpp" #include "syntax_analyser/statement/value/number/number.hpp" #include "syntax_analyser/statement/value/value.hpp" @@ -360,6 +361,105 @@ class Generator { builder.store(builder.add(lhs, rhs, outName), outUint.getAlloc()); break; } + + case StatementType::SUBTRACTION: { + const SubtractionStatement& subtractionStatement = + static_cast(statement); + + std::unique_ptr& out = + symbols.at(subtractionStatement.identifier.name); + + if (out->getType() != BuilderPrimitiveType::UINT) { + throw std::runtime_error( + "Cannot assign subtraction to non-uint type"); + } + + BuilderUintPrimitive& outUint = + static_cast(*out); + + llvm::Value* lhs; + llvm::Value* rhs; + + std::string outName = "subtract_"; + + switch (subtractionStatement.lhs->statementValueType) { + case StatementValueType::IDENTIFIER: { + const IdentifierValue& lhsIdentifierValue = + static_cast( + *subtractionStatement.lhs.get()); + + std::unique_ptr& lhsValue = + symbols.at(lhsIdentifierValue.name); + + if (lhsValue->getType() != BuilderPrimitiveType::UINT) { + throw std::runtime_error("Cannot subtract non-uint types"); + } + + BuilderUintPrimitive& lhsUintValue = + static_cast(*lhsValue); + + lhs = builder.load(lhsUintValue.getLlvmIntegerType(), + lhsUintValue.getAlloc(), + lhsIdentifierValue.name + "_load"); + + outName += lhsIdentifierValue.name; + break; + } + + case StatementValueType::NUMBER: { + const NumberValue& lhsNumberValue = + static_cast( + *subtractionStatement.lhs.get()); + + lhs = builder.createConst8(lhsNumberValue.value); + outName += "const"; + break; + } + } + + outName += "_and_"; + + switch (subtractionStatement.rhs->statementValueType) { + case StatementValueType::IDENTIFIER: { + const IdentifierValue& rhsIdentifierValue = + static_cast( + *subtractionStatement.rhs.get()); + + std::unique_ptr& rhsValue = + symbols.at(rhsIdentifierValue.name); + + if (rhsValue->getType() != BuilderPrimitiveType::UINT) { + throw std::runtime_error("Cannot subtract non-uint types"); + } + + BuilderUintPrimitive& rhsValueUint = + static_cast(*rhsValue); + + rhs = builder.load(rhsValueUint.getLlvmIntegerType(), + rhsValueUint.getAlloc(), + rhsIdentifierValue.name + "_load"); + + outName += rhsIdentifierValue.name; + break; + } + + case StatementValueType::NUMBER: { + const NumberValue& rhsNumberValue = + static_cast( + *subtractionStatement.rhs.get()); + + rhs = builder.createConst8(rhsNumberValue.value); + outName += "const"; + + break; + } + } + + builder.store(builder.subtract(lhs, rhs, outName), + outUint.getAlloc()); + break; + } + case StatementType::PRINT: { const PrintStatement& printStatement = static_cast(statement); diff --git a/src/lexer/lexer.hpp b/src/lexer/lexer.hpp index 20c99fb..7912986 100644 --- a/src/lexer/lexer.hpp +++ b/src/lexer/lexer.hpp @@ -11,6 +11,7 @@ #include "./tokens/primitives/uint64/uint64.hpp" #include "./tokens/operators/addition/addition.hpp" +#include "lexer/tokens/operators/subtraction/subtraction.hpp" #include "lexer/tokens/primitives/uint16/uint16.hpp" #include "lexer/tokens/primitives/uint32/uint32.hpp" #include "lexer/tokens/print/print.hpp" @@ -54,6 +55,8 @@ class Lexer { tokens.addNumber(StringConverter::toUnsignedLongLong(buffer)); } else if (buffer == "+") { tokens.addAddition(AdditionToken()); + } else if (buffer == "-") { + tokens.addSubtraction(SubtractionToken()); } else if (buffer == "return") { tokens.addReturn(ReturnToken()); } else if (buffer == "print") { diff --git a/src/lexer/token_container/token_container.cpp b/src/lexer/token_container/token_container.cpp index a6b73b9..c2aaeb5 100644 --- a/src/lexer/token_container/token_container.cpp +++ b/src/lexer/token_container/token_container.cpp @@ -7,6 +7,7 @@ #include "../tokens/number/number.hpp" #include "../tokens/operators/operator.hpp" #include "../tokens/primitives/primitive.hpp" +#include "lexer/tokens/operators/operator_type.hpp" TokenContainer::TokenContainer() {}; @@ -59,18 +60,27 @@ void TokenContainer::print() const { case OPERATOR: { const OperatorToken& op = static_cast(token); + std::string out = "OPERATOR("; switch (op.operatorType) { case ASSIGNMENT: { - std::cout << "OPERATOR(=)\n"; + out += "="; break; } case ADDITION: { - std::cout << "OPERATOR(+)\n"; + out += "+"; + break; + } + + case SUBTRACTION: { + out += "-"; break; } } + out += ")"; + + std::cout << out << "\n"; break; } diff --git a/src/lexer/token_container/token_container.hpp b/src/lexer/token_container/token_container.hpp index 974d400..a0755b1 100644 --- a/src/lexer/token_container/token_container.hpp +++ b/src/lexer/token_container/token_container.hpp @@ -8,6 +8,7 @@ #include "lexer/tokens/number/number.hpp" #include "lexer/tokens/operators/addition/addition.hpp" #include "lexer/tokens/operators/assignment/assignment.hpp" +#include "lexer/tokens/operators/subtraction/subtraction.hpp" #include "lexer/tokens/primitives/uint16/uint16.hpp" #include "lexer/tokens/primitives/uint32/uint32.hpp" #include "lexer/tokens/primitives/uint64/uint64.hpp" @@ -39,6 +40,10 @@ class TokenContainer { tokens.push_back(std::make_unique(token)); } + void addSubtraction(const SubtractionToken& token) { + tokens.push_back(std::make_unique(token)); + } + void addAssignment(const AssignmentToken& token) { tokens.push_back(std::make_unique(token)); } diff --git a/src/lexer/tokens/operators/operator_type.hpp b/src/lexer/tokens/operators/operator_type.hpp index 7e32b0c..1b2df38 100644 --- a/src/lexer/tokens/operators/operator_type.hpp +++ b/src/lexer/tokens/operators/operator_type.hpp @@ -1,3 +1,3 @@ #pragma once -enum OperatorType { ASSIGNMENT = 1, ADDITION = 2 }; \ No newline at end of file +enum OperatorType { ASSIGNMENT = 1, ADDITION = 2, SUBTRACTION = 3 }; \ No newline at end of file diff --git a/src/lexer/tokens/operators/subtraction/subtraction.cpp b/src/lexer/tokens/operators/subtraction/subtraction.cpp new file mode 100644 index 0000000..8f33a72 --- /dev/null +++ b/src/lexer/tokens/operators/subtraction/subtraction.cpp @@ -0,0 +1,4 @@ +#include "./subtraction.hpp" + +SubtractionToken::SubtractionToken() + : OperatorToken(OperatorType::SUBTRACTION) {} \ No newline at end of file diff --git a/src/lexer/tokens/operators/subtraction/subtraction.hpp b/src/lexer/tokens/operators/subtraction/subtraction.hpp new file mode 100644 index 0000000..d58df88 --- /dev/null +++ b/src/lexer/tokens/operators/subtraction/subtraction.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include "../operator.hpp" + +class SubtractionToken : public OperatorToken { +public: + SubtractionToken(); +}; \ No newline at end of file diff --git a/src/syntax_analyser/abstract_syntax_tree.cpp b/src/syntax_analyser/abstract_syntax_tree.cpp index 319ced6..02699c7 100644 --- a/src/syntax_analyser/abstract_syntax_tree.cpp +++ b/src/syntax_analyser/abstract_syntax_tree.cpp @@ -111,8 +111,9 @@ std::vector> AbstractSyntaxTree::evaluateOperations( const OperatorToken& firstTokenOperator = static_cast(firstToken); - if (firstTokenOperator.operatorType != OperatorType::ADDITION) { - throw std::format_error("Only `+` operator is implemented"); + if (firstTokenOperator.operatorType != OperatorType::ADDITION && + firstTokenOperator.operatorType != OperatorType::SUBTRACTION) { + throw std::format_error("Only `+` and `-` operators are implemented"); } const Token& secondToken = @@ -124,20 +125,50 @@ std::vector> AbstractSyntaxTree::evaluateOperations( "Token adjacent to operator must be an identifier or a value"); } - if (secondToken.tokenType == TokenType::NUMBER) { - statements.push_back(std::make_unique( - IdentifierValue(outputIdentifier), - std::make_unique(outputIdentifier), - std::make_unique( - (static_cast(secondToken)).value))); - } + switch (firstTokenOperator.operatorType) { + case OperatorType::ADDITION: { + if (secondToken.tokenType == TokenType::NUMBER) { + statements.push_back(std::make_unique( + IdentifierValue(outputIdentifier), + std::make_unique(outputIdentifier), + std::make_unique( + (static_cast(secondToken)).value))); + + std::cout << outputIdentifier << " + " + << (static_cast(secondToken)).value + << "\n"; + } - if (secondToken.tokenType == TokenType::IDENTIFIER) { - statements.push_back(std::make_unique( - IdentifierValue(outputIdentifier), - std::make_unique(outputIdentifier), - std::make_unique( - static_cast(secondToken).name))); + if (secondToken.tokenType == TokenType::IDENTIFIER) { + statements.push_back(std::make_unique( + IdentifierValue(outputIdentifier), + std::make_unique(outputIdentifier), + std::make_unique( + static_cast(secondToken).name))); + } + + break; + } + + case OperatorType::SUBTRACTION: { + if (secondToken.tokenType == TokenType::NUMBER) { + statements.push_back(std::make_unique( + IdentifierValue(outputIdentifier), + std::make_unique(outputIdentifier), + std::make_unique( + (static_cast(secondToken)).value))); + } + + if (secondToken.tokenType == TokenType::IDENTIFIER) { + statements.push_back(std::make_unique( + IdentifierValue(outputIdentifier), + std::make_unique(outputIdentifier), + std::make_unique( + static_cast(secondToken).name))); + } + + break; + } } tokensIndex += 2; diff --git a/src/syntax_analyser/program/program.hpp b/src/syntax_analyser/program/program.hpp index 6291983..14edef0 100644 --- a/src/syntax_analyser/program/program.hpp +++ b/src/syntax_analyser/program/program.hpp @@ -9,6 +9,7 @@ #include "syntax_analyser/statement/print/print.hpp" #include "syntax_analyser/statement/return/return.hpp" #include "syntax_analyser/statement/statement.hpp" +#include "syntax_analyser/statement/subtraction/subtraction.hpp" #include "syntax_analyser/statement/value/identifier/identifier.hpp" #include "syntax_analyser/statement/value/number/number.hpp" #include "syntax_analyser/statement/value/value.hpp" @@ -109,6 +110,15 @@ class Program { << rhs << ";\n"; } + void printSubtractionStatement( + const SubtractionStatement& subtractionStatement) const { + std::string lhs = this->getStatementValueString(*subtractionStatement.lhs); + std::string rhs = this->getStatementValueString(*subtractionStatement.rhs); + + std::cout << subtractionStatement.identifier.name << " = " << lhs << " - " + << rhs << ";\n"; + } + void printPrintStatement(const PrintStatement& printStatement) const { std::string value = this->getStatementValueString(*printStatement.value); @@ -166,6 +176,16 @@ class Program { break; } + case StatementType::SUBTRACTION: { + + const SubtractionStatement& subtractionStatement = + static_cast(statement); + + this->printSubtractionStatement(subtractionStatement); + + break; + } + case StatementType::INITIALISATION: { const InitialisationStatement& initialisationStatement = static_cast(statement); diff --git a/src/syntax_analyser/statement/statement_type.hpp b/src/syntax_analyser/statement/statement_type.hpp index 3f8fce2..ec221fd 100644 --- a/src/syntax_analyser/statement/statement_type.hpp +++ b/src/syntax_analyser/statement/statement_type.hpp @@ -3,5 +3,6 @@ enum class StatementType { ASSIGNMENT = 2, RETURN = 3, ADDITION = 4, - PRINT = 5 + SUBTRACTION = 5, + PRINT = 6 }; \ No newline at end of file diff --git a/src/syntax_analyser/statement/subtraction/subtraction.hpp b/src/syntax_analyser/statement/subtraction/subtraction.hpp new file mode 100644 index 0000000..b1a2341 --- /dev/null +++ b/src/syntax_analyser/statement/subtraction/subtraction.hpp @@ -0,0 +1,18 @@ +#pragma once +#include + +#include "syntax_analyser/statement/statement.hpp" +#include "syntax_analyser/statement/value/identifier/identifier.hpp" + +class SubtractionStatement : public Statement { +public: + const IdentifierValue identifier; + const std::unique_ptr lhs; + const std::unique_ptr rhs; + + SubtractionStatement(const IdentifierValue identifier, + std::unique_ptr lhs, + std::unique_ptr rhs) + : Statement(StatementType::SUBTRACTION), identifier(identifier), + lhs(std::move(lhs)), rhs(std::move(rhs)) {}; +}; \ No newline at end of file