From acfd5aa02f97ec67795f8dfc37a76b0a48b98dc9 Mon Sep 17 00:00:00 2001 From: WerWolv Date: Thu, 7 Jan 2021 00:02:51 +0100 Subject: [PATCH] Added if, else and else if to pattern language --- include/lang/ast_node.hpp | 44 +++++++++ include/lang/evaluator.hpp | 1 + include/lang/parser.hpp | 7 ++ include/lang/token.hpp | 102 +++++++++++-------- source/lang/evaluator.cpp | 86 ++++++++++++---- source/lang/lexer.cpp | 31 ++++++ source/lang/parser.cpp | 181 +++++++++++++++++++++++++--------- source/views/view_pattern.cpp | 2 +- 8 files changed, 348 insertions(+), 106 deletions(-) diff --git a/include/lang/ast_node.hpp b/include/lang/ast_node.hpp index d290967c5..570756b76 100644 --- a/include/lang/ast_node.hpp +++ b/include/lang/ast_node.hpp @@ -366,4 +366,48 @@ namespace hex::lang { std::vector m_path; }; + class ASTNodeConditionalStatement : public ASTNode { + public: + explicit ASTNodeConditionalStatement(ASTNode *condition, std::vector trueBody, std::vector falseBody) + : ASTNode(), m_condition(condition), m_trueBody(std::move(trueBody)), m_falseBody(std::move(falseBody)) { } + + ~ASTNodeConditionalStatement() override { + delete this->m_condition; + + for (auto &statement : this->m_trueBody) + delete statement; + for (auto &statement : this->m_falseBody) + delete statement; + } + + ASTNodeConditionalStatement(const ASTNodeConditionalStatement &other) : ASTNode(other) { + this->m_condition = other.m_condition->clone(); + + for (auto &statement : other.m_trueBody) + this->m_trueBody.push_back(statement->clone()); + for (auto &statement : other.m_falseBody) + this->m_falseBody.push_back(statement->clone()); + } + + ASTNode* clone() const override { + return new ASTNodeConditionalStatement(*this); + } + + [[nodiscard]] ASTNode* getCondition() { + return this->m_condition; + } + + [[nodiscard]] const std::vector& getTrueBody() const { + return this->m_trueBody; + } + + [[nodiscard]] const std::vector& getFalseBody() const { + return this->m_falseBody; + } + + private: + ASTNode *m_condition; + std::vector m_trueBody, m_falseBody; + }; + } \ No newline at end of file diff --git a/include/lang/evaluator.hpp b/include/lang/evaluator.hpp index 1dc80403a..ca615eb3e 100644 --- a/include/lang/evaluator.hpp +++ b/include/lang/evaluator.hpp @@ -47,6 +47,7 @@ namespace hex::lang { ASTNodeIntegerLiteral* evaluateMathematicalExpression(ASTNodeNumericExpression *node); PatternData* evaluateBuiltinType(ASTNodeBuiltinType *node); + std::vector evaluateMember(ASTNode *node); PatternData* evaluateStruct(ASTNodeStruct *node); PatternData* evaluateUnion(ASTNodeUnion *node); PatternData* evaluateEnum(ASTNodeEnum *node); diff --git a/include/lang/parser.hpp b/include/lang/parser.hpp index 4b16ba820..74c1f248a 100644 --- a/include/lang/parser.hpp +++ b/include/lang/parser.hpp @@ -59,17 +59,24 @@ namespace hex::lang { ASTNode* parseMultiplicativeExpression(); ASTNode* parseAdditiveExpression(); ASTNode* parseShiftExpression(); + ASTNode* parseRelationExpression(); + ASTNode* parseEqualityExpression(); ASTNode* parseBinaryAndExpression(); ASTNode* parseBinaryXorExpression(); ASTNode* parseBinaryOrExpression(); + ASTNode* parseBooleanAnd(); + ASTNode* parseBooleanXor(); + ASTNode* parseBooleanOr(); ASTNode* parseMathematicalExpression(); + ASTNode* parseConditional(); ASTNode* parseType(s32 startIndex); ASTNode* parseUsingDeclaration(); ASTNode* parsePadding(); ASTNode* parseMemberVariable(); ASTNode* parseMemberArrayVariable(); ASTNode* parseMemberPointerVariable(); + ASTNode* parseMember(); ASTNode* parseStruct(); ASTNode* parseUnion(); ASTNode* parseEnum(); diff --git a/include/lang/token.hpp b/include/lang/token.hpp index 103a21ff6..db2f863dc 100644 --- a/include/lang/token.hpp +++ b/include/lang/token.hpp @@ -28,6 +28,8 @@ namespace hex::lang { Bitfield, LittleEndian, BigEndian, + If, + Else }; enum class Operator { @@ -42,7 +44,16 @@ namespace hex::lang { ShiftRight, BitOr, BitAnd, - BitXor + BitXor, + BoolEquals, + BoolNotEquals, + BoolGreaterThan, + BoolLessThan, + BoolGreaterThanOrEquals, + BoolLessThanOrEquals, + BoolAnd, + BoolOr, + BoolXor }; enum class ValueType { @@ -168,46 +179,57 @@ namespace hex::lang { #define COMPONENT(type, value) hex::lang::Token::Type::type, hex::lang::Token::type::value -#define KEYWORD_STRUCT COMPONENT(Keyword, Struct) -#define KEYWORD_UNION COMPONENT(Keyword, Union) -#define KEYWORD_USING COMPONENT(Keyword, Using) -#define KEYWORD_ENUM COMPONENT(Keyword, Enum) -#define KEYWORD_BITFIELD COMPONENT(Keyword, Bitfield) -#define KEYWORD_LE COMPONENT(Keyword, LittleEndian) -#define KEYWORD_BE COMPONENT(Keyword, BigEndian) +#define KEYWORD_STRUCT COMPONENT(Keyword, Struct) +#define KEYWORD_UNION COMPONENT(Keyword, Union) +#define KEYWORD_USING COMPONENT(Keyword, Using) +#define KEYWORD_ENUM COMPONENT(Keyword, Enum) +#define KEYWORD_BITFIELD COMPONENT(Keyword, Bitfield) +#define KEYWORD_LE COMPONENT(Keyword, LittleEndian) +#define KEYWORD_BE COMPONENT(Keyword, BigEndian) +#define KEYWORD_IF COMPONENT(Keyword, If) +#define KEYWORD_ELSE COMPONENT(Keyword, Else) -#define INTEGER hex::lang::Token::Type::Integer, hex::lang::Token::IntegerLiteral({ hex::lang::Token::ValueType::Any, 0xFFFF'FFFF'FFFF'FFFF }) -#define IDENTIFIER hex::lang::Token::Type::Identifier, "" +#define INTEGER hex::lang::Token::Type::Integer, hex::lang::Token::IntegerLiteral({ hex::lang::Token::ValueType::Any, 0xFFFF'FFFF'FFFF'FFFF }) +#define IDENTIFIER hex::lang::Token::Type::Identifier, "" -#define OPERATOR_AT COMPONENT(Operator, AtDeclaration) -#define OPERATOR_ASSIGNMENT COMPONENT(Operator, Assignment) -#define OPERATOR_INHERIT COMPONENT(Operator, Inherit) -#define OPERATOR_PLUS COMPONENT(Operator, Plus) -#define OPERATOR_MINUS COMPONENT(Operator, Minus) -#define OPERATOR_STAR COMPONENT(Operator, Star) -#define OPERATOR_SLASH COMPONENT(Operator, Slash) -#define OPERATOR_SHIFTLEFT COMPONENT(Operator, ShiftLeft) -#define OPERATOR_SHIFTRIGHT COMPONENT(Operator, ShiftRight) -#define OPERATOR_BITOR COMPONENT(Operator, BitOr) -#define OPERATOR_BITAND COMPONENT(Operator, BitAnd) -#define OPERATOR_BITXOR COMPONENT(Operator, BitXor) +#define OPERATOR_AT COMPONENT(Operator, AtDeclaration) +#define OPERATOR_ASSIGNMENT COMPONENT(Operator, Assignment) +#define OPERATOR_INHERIT COMPONENT(Operator, Inherit) +#define OPERATOR_PLUS COMPONENT(Operator, Plus) +#define OPERATOR_MINUS COMPONENT(Operator, Minus) +#define OPERATOR_STAR COMPONENT(Operator, Star) +#define OPERATOR_SLASH COMPONENT(Operator, Slash) +#define OPERATOR_SHIFTLEFT COMPONENT(Operator, ShiftLeft) +#define OPERATOR_SHIFTRIGHT COMPONENT(Operator, ShiftRight) +#define OPERATOR_BITOR COMPONENT(Operator, BitOr) +#define OPERATOR_BITAND COMPONENT(Operator, BitAnd) +#define OPERATOR_BITXOR COMPONENT(Operator, BitXor) +#define OPERATOR_BOOLEQUALS COMPONENT(Operator, BoolEquals) +#define OPERATOR_BOOLNOTEQUALS COMPONENT(Operator, BoolNotEquals) +#define OPERATOR_BOOLGREATERTHAN COMPONENT(Operator, BoolGreaterThan) +#define OPERATOR_BOOLLESSTHAN COMPONENT(Operator, BoolLessThan) +#define OPERATOR_BOOLGREATERTHANOREQUALS COMPONENT(Operator, BoolGreaterThanOrEquals) +#define OPERATOR_BOOLLESSTHANOREQUALS COMPONENT(Operator, BoolLessThanOrEquals) +#define OPERATOR_BOOLAND COMPONENT(Operator, BoolAnd) +#define OPERATOR_BOOLOR COMPONENT(Operator, BoolOr) +#define OPERATOR_BOOLXOR COMPONENT(Operator, BoolXor) -#define VALUETYPE_CUSTOMTYPE COMPONENT(ValueType, CustomType) -#define VALUETYPE_PADDING COMPONENT(ValueType, Padding) -#define VALUETYPE_UNSIGNED COMPONENT(ValueType, Unsigned) -#define VALUETYPE_SIGNED COMPONENT(ValueType, Signed) -#define VALUETYPE_FLOATINGPOINT COMPONENT(ValueType, FloatingPoint) -#define VALUETYPE_INTEGER COMPONENT(ValueType, Integer) -#define VALUETYPE_ANY COMPONENT(ValueType, Any) +#define VALUETYPE_CUSTOMTYPE COMPONENT(ValueType, CustomType) +#define VALUETYPE_PADDING COMPONENT(ValueType, Padding) +#define VALUETYPE_UNSIGNED COMPONENT(ValueType, Unsigned) +#define VALUETYPE_SIGNED COMPONENT(ValueType, Signed) +#define VALUETYPE_FLOATINGPOINT COMPONENT(ValueType, FloatingPoint) +#define VALUETYPE_INTEGER COMPONENT(ValueType, Integer) +#define VALUETYPE_ANY COMPONENT(ValueType, Any) -#define SEPARATOR_ROUNDBRACKETOPEN COMPONENT(Separator, RoundBracketOpen) -#define SEPARATOR_ROUNDBRACKETCLOSE COMPONENT(Separator, RoundBracketClose) -#define SEPARATOR_CURLYBRACKETOPEN COMPONENT(Separator, CurlyBracketOpen) -#define SEPARATOR_CURLYBRACKETCLOSE COMPONENT(Separator, CurlyBracketClose) -#define SEPARATOR_SQUAREBRACKETOPEN COMPONENT(Separator, SquareBracketOpen) -#define SEPARATOR_SQUAREBRACKETCLOSE COMPONENT(Separator, SquareBracketClose) -#define SEPARATOR_COMMA COMPONENT(Separator, Comma) -#define SEPARATOR_DOT COMPONENT(Separator, Dot) -#define SEPARATOR_SCOPE_RESOLUTION COMPONENT(Separator, ScopeResolution) -#define SEPARATOR_ENDOFEXPRESSION COMPONENT(Separator, EndOfExpression) -#define SEPARATOR_ENDOFPROGRAM COMPONENT(Separator, EndOfProgram) \ No newline at end of file +#define SEPARATOR_ROUNDBRACKETOPEN COMPONENT(Separator, RoundBracketOpen) +#define SEPARATOR_ROUNDBRACKETCLOSE COMPONENT(Separator, RoundBracketClose) +#define SEPARATOR_CURLYBRACKETOPEN COMPONENT(Separator, CurlyBracketOpen) +#define SEPARATOR_CURLYBRACKETCLOSE COMPONENT(Separator, CurlyBracketClose) +#define SEPARATOR_SQUAREBRACKETOPEN COMPONENT(Separator, SquareBracketOpen) +#define SEPARATOR_SQUAREBRACKETCLOSE COMPONENT(Separator, SquareBracketClose) +#define SEPARATOR_COMMA COMPONENT(Separator, Comma) +#define SEPARATOR_DOT COMPONENT(Separator, Dot) +#define SEPARATOR_SCOPE_RESOLUTION COMPONENT(Separator, ScopeResolution) +#define SEPARATOR_ENDOFEXPRESSION COMPONENT(Separator, EndOfExpression) +#define SEPARATOR_ENDOFPROGRAM COMPONENT(Separator, EndOfProgram) \ No newline at end of file diff --git a/source/lang/evaluator.cpp b/source/lang/evaluator.cpp index d9c297bfb..86549c6d8 100644 --- a/source/lang/evaluator.cpp +++ b/source/lang/evaluator.cpp @@ -79,6 +79,18 @@ namespace hex::lang { case 16: return new ASTNodeIntegerLiteral({ Token::ValueType::Signed128Bit, *reinterpret_cast(value) }); default: throwEvaluateError("invalid rvalue size", node->getLineNumber()); } + } else if (auto enumPattern = dynamic_cast(currPattern); enumPattern != nullptr) { + u8 value[enumPattern->getSize()]; + this->m_provider->read(enumPattern->getOffset(), value, enumPattern->getSize()); + + switch (enumPattern->getSize()) { + case 1: return new ASTNodeIntegerLiteral({ Token::ValueType::Signed8Bit, *reinterpret_cast(value) }); + case 2: return new ASTNodeIntegerLiteral({ Token::ValueType::Signed16Bit, *reinterpret_cast(value) }); + case 4: return new ASTNodeIntegerLiteral({ Token::ValueType::Signed32Bit, *reinterpret_cast(value) }); + case 8: return new ASTNodeIntegerLiteral({ Token::ValueType::Signed64Bit, *reinterpret_cast(value) }); + case 16: return new ASTNodeIntegerLiteral({ Token::ValueType::Signed128Bit, *reinterpret_cast(value) }); + default: throwEvaluateError("invalid rvalue size", node->getLineNumber()); + } } else throwEvaluateError("tried to use non-integer value in numeric expression", node->getLineNumber()); } @@ -158,6 +170,24 @@ namespace hex::lang { return new ASTNodeIntegerLiteral({ newType, bitXor(leftValue, rightValue) }); case Token::Operator::BitOr: return new ASTNodeIntegerLiteral({ newType, bitOr(leftValue, rightValue) }); + case Token::Operator::BoolEquals: + return new ASTNodeIntegerLiteral({ newType, leftValue == rightValue }); + case Token::Operator::BoolNotEquals: + return new ASTNodeIntegerLiteral({ newType, leftValue != rightValue }); + case Token::Operator::BoolGreaterThan: + return new ASTNodeIntegerLiteral({ newType, leftValue > rightValue }); + case Token::Operator::BoolLessThan: + return new ASTNodeIntegerLiteral({ newType, leftValue < rightValue }); + case Token::Operator::BoolGreaterThanOrEquals: + return new ASTNodeIntegerLiteral({ newType, leftValue >= rightValue }); + case Token::Operator::BoolLessThanOrEquals: + return new ASTNodeIntegerLiteral({ newType, leftValue <= rightValue }); + case Token::Operator::BoolAnd: + return new ASTNodeIntegerLiteral({ newType, leftValue && rightValue }); + case Token::Operator::BoolXor: + return new ASTNodeIntegerLiteral({ newType, leftValue && !rightValue || !leftValue && rightValue }); + case Token::Operator::BoolOr: + return new ASTNodeIntegerLiteral({ newType, leftValue || rightValue }); default: throwEvaluateError("invalid operator used in mathematical expression", left->getLineNumber()); } @@ -220,6 +250,39 @@ namespace hex::lang { return pattern; } + std::vector Evaluator::evaluateMember(ASTNode *node) { + this->m_currEndian.reset(); + + if (auto memberVariableNode = dynamic_cast(node); memberVariableNode != nullptr) + return { this->evaluateVariable(memberVariableNode) }; + else if (auto memberArrayNode = dynamic_cast(node); memberArrayNode != nullptr) + return { this->evaluateArray(memberArrayNode) }; + else if (auto memberPointerNode = dynamic_cast(node); memberPointerNode != nullptr) + return { this->evaluatePointer(memberPointerNode) }; + else if (auto conditionalNode = dynamic_cast(node); conditionalNode != nullptr) { + auto condition = this->evaluateMathematicalExpression(static_cast(conditionalNode->getCondition())); + + std::vector patterns; + if (std::visit([](auto &&value) { return value != 0; }, condition->getValue())) { + for (auto &statement : conditionalNode->getTrueBody()) { + auto statementPatterns = this->evaluateMember(statement); + std::copy(statementPatterns.begin(), statementPatterns.end(), std::back_inserter(patterns)); + } + } else { + for (auto &statement : conditionalNode->getFalseBody()) { + auto statementPatterns = this->evaluateMember(statement); + std::copy(statementPatterns.begin(), statementPatterns.end(), std::back_inserter(patterns)); + } + } + + delete condition; + + return patterns; + } + else + throwEvaluateError("invalid struct member", node->getLineNumber()); + } + PatternData* Evaluator::evaluateStruct(ASTNodeStruct *node) { std::vector memberPatterns; @@ -228,16 +291,8 @@ namespace hex::lang { auto startOffset = this->m_currOffset; for (auto &member : node->getMembers()) { - if (auto memberVariableNode = dynamic_cast(member); memberVariableNode != nullptr) - memberPatterns.emplace_back(this->evaluateVariable(memberVariableNode)); - else if (auto memberArrayNode = dynamic_cast(member); memberArrayNode != nullptr) - memberPatterns.emplace_back(this->evaluateArray(memberArrayNode)); - else if (auto memberPointerNode = dynamic_cast(member); memberPointerNode != nullptr) - memberPatterns.emplace_back(this->evaluatePointer(memberPointerNode)); - else - throwEvaluateError("invalid struct member", member->getLineNumber()); - - this->m_currEndian.reset(); + auto newMembers = this->evaluateMember(member); + std::copy(newMembers.begin(), newMembers.end(), std::back_inserter(memberPatterns)); } return new PatternDataStruct(startOffset, this->m_currOffset - startOffset, memberPatterns); @@ -251,17 +306,10 @@ namespace hex::lang { auto startOffset = this->m_currOffset; for (auto &member : node->getMembers()) { - if (auto memberVariableNode = dynamic_cast(member); memberVariableNode != nullptr) - memberPatterns.emplace_back(this->evaluateVariable(memberVariableNode)); - else if (auto memberArrayNode = dynamic_cast(member); memberArrayNode != nullptr) - memberPatterns.emplace_back(this->evaluateArray(memberArrayNode)); - else if (auto memberPointerNode = dynamic_cast(member); memberPointerNode != nullptr) - memberPatterns.emplace_back(this->evaluatePointer(memberPointerNode)); - else - throwEvaluateError("invalid union member", member->getLineNumber()); + auto newMembers = this->evaluateMember(member); + std::copy(newMembers.begin(), newMembers.end(), std::back_inserter(memberPatterns)); this->m_currOffset = startOffset; - this->m_currEndian.reset(); } return new PatternDataUnion(startOffset, this->m_currOffset - startOffset, memberPatterns); diff --git a/source/lang/lexer.cpp b/source/lang/lexer.cpp index e4e2817ec..7ab6c825e 100644 --- a/source/lang/lexer.cpp +++ b/source/lang/lexer.cpp @@ -188,6 +188,27 @@ namespace hex::lang { } else if (c == '@') { tokens.emplace_back(TOKEN(Operator, AtDeclaration)); offset += 1; + } else if (code.substr(offset, 2) == "==") { + tokens.emplace_back(TOKEN(Operator, BoolEquals)); + offset += 2; + } else if (code.substr(offset, 2) == "!=") { + tokens.emplace_back(TOKEN(Operator, BoolNotEquals)); + offset += 2; + } else if (code.substr(offset, 2) == ">=") { + tokens.emplace_back(TOKEN(Operator, BoolGreaterThanOrEquals)); + offset += 2; + } else if (code.substr(offset, 2) == "<=") { + tokens.emplace_back(TOKEN(Operator, BoolLessThanOrEquals)); + offset += 2; + } else if (code.substr(offset, 2) == "&&") { + tokens.emplace_back(TOKEN(Operator, BoolAnd)); + offset += 2; + } else if (code.substr(offset, 2) == "||") { + tokens.emplace_back(TOKEN(Operator, BoolOr)); + offset += 2; + } else if (code.substr(offset, 2) == "^^") { + tokens.emplace_back(TOKEN(Operator, BoolXor)); + offset += 2; } else if (c == '=') { tokens.emplace_back(TOKEN(Operator, Assignment)); offset += 1; @@ -215,6 +236,12 @@ namespace hex::lang { } else if (code.substr(offset, 2) == ">>") { tokens.emplace_back(TOKEN(Operator, ShiftRight)); offset += 2; + } else if (c == '>') { + tokens.emplace_back(TOKEN(Operator, BoolGreaterThan)); + offset += 1; + } else if (c == '<') { + tokens.emplace_back(TOKEN(Operator, BoolLessThan)); + offset += 1; } else if (c == '|') { tokens.emplace_back(TOKEN(Operator, BitOr)); offset += 1; @@ -276,6 +303,10 @@ namespace hex::lang { tokens.emplace_back(TOKEN(Keyword, BigEndian)); else if (identifier == "le") tokens.emplace_back(TOKEN(Keyword, LittleEndian)); + else if (identifier == "if") + tokens.emplace_back(TOKEN(Keyword, If)); + else if (identifier == "else") + tokens.emplace_back(TOKEN(Keyword, Else)); // Check for built-in types else if (identifier == "u8") diff --git a/source/lang/parser.cpp b/source/lang/parser.cpp index 152c35266..571c90365 100644 --- a/source/lang/parser.cpp +++ b/source/lang/parser.cpp @@ -55,8 +55,9 @@ namespace hex::lang { if (!MATCHES(sequence(SEPARATOR_ROUNDBRACKETCLOSE))) throwParseError("expected closing parenthesis"); return node; - } else if (MATCHES(sequence(IDENTIFIER) && peek(SEPARATOR_SCOPE_RESOLUTION))) { + } else if (MATCHES(sequence(IDENTIFIER, SEPARATOR_SCOPE_RESOLUTION))) { std::vector path; + this->m_curr--; return this->parseScopeResolution(path); } else if (MATCHES(sequence(IDENTIFIER))) { @@ -72,10 +73,8 @@ namespace hex::lang { auto node = this->parseFactor(); while (MATCHES(variant(OPERATOR_STAR, OPERATOR_SLASH))) { - if (peek(OPERATOR_STAR, -1)) - node = new ASTNodeNumericExpression(node, this->parseFactor(), Token::Operator::Star); - else - node = new ASTNodeNumericExpression(node, this->parseFactor(), Token::Operator::Slash); + auto op = getValue(-1); + node = new ASTNodeNumericExpression(node, this->parseFactor(), op); } return node; @@ -86,35 +85,55 @@ namespace hex::lang { auto node = this->parseMultiplicativeExpression(); while (MATCHES(variant(OPERATOR_PLUS, OPERATOR_MINUS))) { - if (peek(OPERATOR_PLUS, -1)) - node = new ASTNodeNumericExpression(node, this->parseMultiplicativeExpression(), Token::Operator::Plus); - else - node = new ASTNodeNumericExpression(node, this->parseMultiplicativeExpression(), Token::Operator::Minus); + auto op = getValue(-1); + node = new ASTNodeNumericExpression(node, this->parseMultiplicativeExpression(), op); } return node; } - // (parseAdditiveExpression) <>>|<<> (parseAdditiveExpression) + // (parseAdditiveExpression) < >>|<< > (parseAdditiveExpression) ASTNode* Parser::parseShiftExpression() { auto node = this->parseAdditiveExpression(); while (MATCHES(variant(OPERATOR_SHIFTLEFT, OPERATOR_SHIFTRIGHT))) { - if (peek(OPERATOR_SHIFTLEFT, -1)) - node = new ASTNodeNumericExpression(node, this->parseAdditiveExpression(), Token::Operator::ShiftLeft); - else - node = new ASTNodeNumericExpression(node, this->parseAdditiveExpression(), Token::Operator::ShiftRight); + auto op = getValue(-1); + node = new ASTNodeNumericExpression(node, this->parseAdditiveExpression(), op); } return node; } - // (parseShiftExpression) & (parseShiftExpression) - ASTNode* Parser::parseBinaryAndExpression() { + // (parseAdditiveExpression) < >=|<=|>|< > (parseAdditiveExpression) + ASTNode* Parser::parseRelationExpression() { auto node = this->parseShiftExpression(); + while (MATCHES(sequence(OPERATOR_BOOLGREATERTHAN) || sequence(OPERATOR_BOOLLESSTHAN) || sequence(OPERATOR_BOOLGREATERTHANOREQUALS) || sequence(OPERATOR_BOOLLESSTHANOREQUALS))) { + auto op = getValue(-1); + node = new ASTNodeNumericExpression(node, this->parseShiftExpression(), op); + } + + return node; + } + + // (parseRelationExpression) <==|!=> (parseRelationExpression) + ASTNode* Parser::parseEqualityExpression() { + auto node = this->parseRelationExpression(); + + while (MATCHES(sequence(OPERATOR_BOOLEQUALS) || sequence(OPERATOR_BOOLNOTEQUALS))) { + auto op = getValue(-1); + node = new ASTNodeNumericExpression(node, this->parseRelationExpression(), op); + } + + return node; + } + + // (parseEqualityExpression) & (parseEqualityExpression) + ASTNode* Parser::parseBinaryAndExpression() { + auto node = this->parseEqualityExpression(); + while (MATCHES(sequence(OPERATOR_BITAND))) { - node = new ASTNodeNumericExpression(node, this->parseShiftExpression(), Token::Operator::BitAnd); + node = new ASTNodeNumericExpression(node, this->parseEqualityExpression(), Token::Operator::BitAnd); } return node; @@ -142,9 +161,80 @@ namespace hex::lang { return node; } + // (parseBinaryOrExpression) && (parseBinaryOrExpression) + ASTNode* Parser::parseBooleanAnd() { + auto node = this->parseBinaryOrExpression(); + + while (MATCHES(sequence(OPERATOR_BOOLAND))) { + node = new ASTNodeNumericExpression(node, this->parseBinaryOrExpression(), Token::Operator::BitOr); + } + + return node; + } + + // (parseBooleanAnd) ^^ (parseBooleanAnd) + ASTNode* Parser::parseBooleanXor() { + auto node = this->parseBooleanAnd(); + + while (MATCHES(sequence(OPERATOR_BOOLXOR))) { + node = new ASTNodeNumericExpression(node, this->parseBooleanAnd(), Token::Operator::BitOr); + } + + return node; + } + + // (parseBooleanXor) || (parseBooleanXor) + ASTNode* Parser::parseBooleanOr() { + auto node = this->parseBooleanXor(); + + while (MATCHES(sequence(OPERATOR_BOOLOR))) { + node = new ASTNodeNumericExpression(node, this->parseBooleanXor(), Token::Operator::BitOr); + } + + return node; + } + // (parseBinaryOrExpression) ASTNode* Parser::parseMathematicalExpression() { - return this->parseBinaryOrExpression(); + return this->parseBooleanOr(); + } + + + /* Control flow */ + + // if ((parseMathematicalExpression)) { (parseMember) } + ASTNode* Parser::parseConditional() { + auto condition = parseMathematicalExpression(); + std::vector trueBody, falseBody; + + ScopeExit cleanup([&]{ + delete condition; + for (auto &statement : trueBody) + delete statement; + for (auto &statement : falseBody) + delete statement; + }); + + if (MATCHES(sequence(SEPARATOR_ROUNDBRACKETCLOSE, SEPARATOR_CURLYBRACKETOPEN))) { + while (!MATCHES(sequence(SEPARATOR_CURLYBRACKETCLOSE))) { + trueBody.push_back(parseMember()); + } + } else if (MATCHES(sequence(SEPARATOR_ROUNDBRACKETCLOSE))) { + trueBody.push_back(parseMember()); + } else + throwParseError("expected body of conditional statement"); + + if (MATCHES(sequence(KEYWORD_ELSE, SEPARATOR_CURLYBRACKETOPEN))) { + while (!MATCHES(sequence(SEPARATOR_CURLYBRACKETCLOSE))) { + falseBody.push_back(parseMember()); + } + } else if (MATCHES(sequence(KEYWORD_ELSE))) { + falseBody.push_back(parseMember()); + } + + cleanup.release(); + + return new ASTNodeConditionalStatement(condition, trueBody, falseBody); } /* Type declarations */ @@ -235,6 +325,31 @@ namespace hex::lang { return new ASTNodePointerVariableDecl(name, temporaryPointerType->getType()->clone(), temporarySizeType->getType()->clone()); } + // [(parsePadding)|(parseMemberVariable)|(parseMemberArrayVariable)|(parseMemberPointerVariable)] + ASTNode* Parser::parseMember() { + ASTNode *member; + + if (MATCHES(sequence(VALUETYPE_PADDING, SEPARATOR_SQUAREBRACKETOPEN))) + member = parsePadding(); + else if (MATCHES((optional(KEYWORD_BE), optional(KEYWORD_LE)) && variant(IDENTIFIER, VALUETYPE_ANY) && sequence(IDENTIFIER, SEPARATOR_SQUAREBRACKETOPEN))) + member = parseMemberArrayVariable(); + else if (MATCHES((optional(KEYWORD_BE), optional(KEYWORD_LE)) && variant(IDENTIFIER, VALUETYPE_ANY) && sequence(IDENTIFIER))) + member = parseMemberVariable(); + else if (MATCHES((optional(KEYWORD_BE), optional(KEYWORD_LE)) && variant(IDENTIFIER, VALUETYPE_ANY) && sequence(OPERATOR_STAR, IDENTIFIER, OPERATOR_INHERIT))) + member = parseMemberPointerVariable(); + else if (MATCHES(sequence(KEYWORD_IF, SEPARATOR_ROUNDBRACKETOPEN))) + return parseConditional(); + else if (MATCHES(sequence(SEPARATOR_ENDOFPROGRAM))) + throwParseError("unexpected end of program", -2); + else + throwParseError("invalid struct member", 0); + + if (!MATCHES(sequence(SEPARATOR_ENDOFEXPRESSION))) + throwParseError("missing ';' at end of expression", -1); + + return member; + } + // struct Identifier { <(parseMember)...> } ASTNode* Parser::parseStruct() { const auto structNode = new ASTNodeStruct(); @@ -242,21 +357,7 @@ namespace hex::lang { ScopeExit structGuard([&]{ delete structNode; }); while (!MATCHES(sequence(SEPARATOR_CURLYBRACKETCLOSE))) { - if (MATCHES(sequence(VALUETYPE_PADDING, SEPARATOR_SQUAREBRACKETOPEN))) - structNode->addMember(parsePadding()); - else if (MATCHES((optional(KEYWORD_BE), optional(KEYWORD_LE)) && variant(IDENTIFIER, VALUETYPE_ANY) && sequence(IDENTIFIER, SEPARATOR_SQUAREBRACKETOPEN))) - structNode->addMember(parseMemberArrayVariable()); - else if (MATCHES((optional(KEYWORD_BE), optional(KEYWORD_LE)) && variant(IDENTIFIER, VALUETYPE_ANY) && sequence(IDENTIFIER))) - structNode->addMember(parseMemberVariable()); - else if (MATCHES((optional(KEYWORD_BE), optional(KEYWORD_LE)) && variant(IDENTIFIER, VALUETYPE_ANY) && sequence(OPERATOR_STAR, IDENTIFIER, OPERATOR_INHERIT))) - structNode->addMember(parseMemberPointerVariable()); - else if (MATCHES(sequence(SEPARATOR_ENDOFPROGRAM))) - throwParseError("unexpected end of program", -2); - else - throwParseError("invalid struct member", 0); - - if (!MATCHES(sequence(SEPARATOR_ENDOFEXPRESSION))) - throwParseError("missing ';' at end of expression", -1); + structNode->addMember(parseMember()); } structGuard.release(); @@ -271,19 +372,7 @@ namespace hex::lang { ScopeExit unionGuard([&]{ delete unionNode; }); while (!MATCHES(sequence(SEPARATOR_CURLYBRACKETCLOSE))) { - if (MATCHES((optional(KEYWORD_BE), optional(KEYWORD_LE)) && variant(IDENTIFIER, VALUETYPE_ANY) && sequence(IDENTIFIER, SEPARATOR_SQUAREBRACKETOPEN))) - unionNode->addMember(parseMemberArrayVariable()); - else if (MATCHES((optional(KEYWORD_BE), optional(KEYWORD_LE)) && variant(IDENTIFIER, VALUETYPE_ANY) && sequence(IDENTIFIER))) - unionNode->addMember(parseMemberVariable()); - else if (MATCHES((optional(KEYWORD_BE), optional(KEYWORD_LE)) && variant(IDENTIFIER, VALUETYPE_ANY) && sequence(OPERATOR_STAR, IDENTIFIER, OPERATOR_INHERIT))) - unionNode->addMember(parseMemberPointerVariable()); - else if (MATCHES(sequence(SEPARATOR_ENDOFPROGRAM))) - throwParseError("unexpected end of program", -2); - else - throwParseError("invalid union member", 0); - - if (!MATCHES(sequence(SEPARATOR_ENDOFEXPRESSION))) - throwParseError("missing ';' at end of expression", -1); + unionNode->addMember(parseMember()); } unionGuard.release(); diff --git a/source/views/view_pattern.cpp b/source/views/view_pattern.cpp index 7b948fe5a..74831a871 100644 --- a/source/views/view_pattern.cpp +++ b/source/views/view_pattern.cpp @@ -18,7 +18,7 @@ namespace hex { static TextEditor::LanguageDefinition langDef; if (!initialized) { static const char* const keywords[] = { - "using", "struct", "union", "enum", "bitfield", "be", "le" + "using", "struct", "union", "enum", "bitfield", "be", "le", "if", "else" }; for (auto& k : keywords) langDef.mKeywords.insert(k);