diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..64b5d4d --- /dev/null +++ b/.clang-format @@ -0,0 +1,107 @@ +--- +Language: Cpp + +DisableFormat: false +Standard: Latest +BasedOnStyle: WebKit +TabWidth: 4 +IndentWidth: 4 +ContinuationIndentWidth: 4 +ConstructorInitializerIndentWidth: 1 +UseTab: Never +ColumnLimit: 120 + +AccessModifierOffset: -4 +AlignAfterOpenBracket: AlwaysBreak +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignConsecutiveMacros: false +AlignEscapedNewlines: DontAlign +AlignOperands: false +AlignTrailingComments: false +AllowAllArgumentsOnNextLine: false +AllowAllConstructorInitializersOnNextLine: false +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: false +AllowShortLambdasOnASingleLine: Inline +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: No +BinPackArguments: false +BinPackParameters: false + +# Configure each individual brace in BraceWrapping +BreakBeforeBraces: Custom +# Control of individual brace wrapping cases +BraceWrapping: + AfterCaseLabel: true + AfterClass: false + AfterControlStatement: Always + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterStruct: true + AfterUnion: true + AfterExternBlock: true + BeforeCatch: true + BeforeElse: true + BeforeLambdaBody: true + IndentBraces: false + SplitEmptyFunction: false + SplitEmptyRecord: false + SplitEmptyNamespace: true + +BreakAfterJavaFieldAnnotations: true +BreakBeforeTernaryOperators: false +BreakConstructorInitializers: BeforeColon +BreakInheritanceList: BeforeColon +BreakStringLiterals: false +CommentPragmas: "^ IWYU pragma:" +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: false +Cpp11BracedListStyle: true +FixNamespaceComments: false +IndentCaseLabels: true +IndentPPDirectives: BeforeHash +IndentWrappedFunctionNames: false +KeepEmptyLinesAtTheStartOfBlocks: false +MacroBlockBegin: "" +MacroBlockEnd: "" +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: All +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 + +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerAlignment: Middle +# QualifierAlignment: Right # Only supported in clang-format 14+ +# ReferenceAlignmentStyle: Middle # Only supported in clang-format 14+ +SortIncludes: true +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: true +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: Never +SpaceBeforeRangeBasedForLoopColon: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInCStyleCastParentheses: false +SpacesInContainerLiterals: false +SpacesInParentheses: false +SpacesInSquareBrackets: false + +# Comments are for developers, they should arrange them +ReflowComments: false + +IncludeBlocks: Preserve +--- diff --git a/bin/fibonacci.wasm b/bin/fibonacci.wasm new file mode 100644 index 0000000..ce150ca --- /dev/null +++ b/bin/fibonacci.wasm @@ -0,0 +1,9 @@ +# Get a number from STDIN + +# Clobbers registers +get_user_integer: + seti [STRING_STORAGE] + +seti %A $0; +seti %B $100; +int $5; \ No newline at end of file diff --git a/compile_flags.txt b/compile_flags.txt new file mode 100644 index 0000000..e6a85fe --- /dev/null +++ b/compile_flags.txt @@ -0,0 +1,5 @@ +-xc++ +-Wall +-Wextra +-Iinclude/ +-std=c++17 \ No newline at end of file diff --git a/include/compile/compiler.hpp b/include/compile/compiler.hpp index 22762a9..ac9e2a6 100644 --- a/include/compile/compiler.hpp +++ b/include/compile/compiler.hpp @@ -2,24 +2,19 @@ #include #include #include -#include #include +#include namespace Compile { - class Compiler - { - private: - std::unordered_map jumpLabelLocations; - std::vector> unresolvedJumpLabels; + class Compiler { + private: + std::unordered_map jumpLabelLocations; + std::vector> unresolvedJumpLabels; - void InsertAsBytes( - Token::Token const & token, - std::vector & bytes); + void InsertAsBytes(Token::Token const & token, std::vector & bytes); - public: - bool Compile( - std::vector const & tokens, - std::vector & bytes); - }; + public: + bool Compile(std::vector const & tokens, std::vector & bytes); + }; } \ No newline at end of file diff --git a/include/compile/errors.hpp b/include/compile/errors.hpp index 7eb6e0a..a7a3270 100644 --- a/include/compile/errors.hpp +++ b/include/compile/errors.hpp @@ -4,25 +4,24 @@ namespace Compile { - class CompilationError - { - public: - Token::Token errorToken; + class CompilationError { + public: + Token::Token errorToken; - CompilationError(std::string const & message, Token::Token const & token); + CompilationError(std::string const & message, Token::Token const & token); - static CompilationError CreateExpectedArgumentError(Token::Token const & token); - static CompilationError CreateExpectedLabelError(Token::Token const & token); - static CompilationError CreateExpectedImmediateError(Token::Token const & token); - static CompilationError CreateExpectedImmediateOrRegisterOrMemory(Token::Token const & token); - static CompilationError CreateExpectedRegisterError(Token::Token const & token); - static CompilationError CreateExpectedRegisterOrMemoryError(Token::Token const & token); + static CompilationError CreateExpectedArgumentError(Token::Token const & token); + static CompilationError CreateExpectedLabelError(Token::Token const & token); + static CompilationError CreateExpectedImmediateError(Token::Token const & token); + static CompilationError CreateExpectedImmediateOrRegisterOrMemory(Token::Token const & token); + static CompilationError CreateExpectedRegisterError(Token::Token const & token); + static CompilationError CreateExpectedRegisterOrMemoryError(Token::Token const & token); - static CompilationError CreateExpectedOperandError(Token::Token const & token); - static CompilationError CreateTooManyArgumentsError(Token::Token const & token); - static CompilationError CreateTooFewArgumentsError(Token::Token const & token); - static CompilationError CreateExpectedEndOfStatementError(Token::Token const & token); - static CompilationError CreateDuplicateLabelError(Token::Token const & token); - static CompilationError CreateNonExistingLabelError(Token::Token const & token); - }; + static CompilationError CreateExpectedOperandError(Token::Token const & token); + static CompilationError CreateTooManyArgumentsError(Token::Token const & token); + static CompilationError CreateTooFewArgumentsError(Token::Token const & token); + static CompilationError CreateExpectedEndOfStatementError(Token::Token const & token); + static CompilationError CreateDuplicateLabelError(Token::Token const & token); + static CompilationError CreateNonExistingLabelError(Token::Token const & token); + }; } \ No newline at end of file diff --git a/include/execute/argumentvalue.hpp b/include/execute/argumentvalue.hpp index be5126f..7b37bc3 100644 --- a/include/execute/argumentvalue.hpp +++ b/include/execute/argumentvalue.hpp @@ -1,37 +1,34 @@ #pragma once -#include #include #include #include #include +#include #include namespace Execute { - enum class ArgumentType - { - Immediate, - Register, - Memory - }; + enum class ArgumentType + { + Immediate, + Register, + Memory + }; - class ArgumentValue - { - private: - ArgumentType type; - ArgumentType memoryValueType; - std::variant data; + class ArgumentValue { + private: + ArgumentType type; + ArgumentType memoryValueType; + std::variant data; - int & GetRegister(State & state) const; - std::uint8_t * GetMemory(State & state) const; + int & GetRegister(State & state) const; + std::uint8_t * GetMemory(State & state) const; - public: - void Write(int const value, State & state) const; - int Read(State & state) const; + public: + void Write(int const value, State & state) const; + int Read(State & state) const; - // Returns the size of the argument in bytes - std::size_t Parse( - std::vector const & memory, - std::size_t const pos); - }; + // Returns the size of the argument in bytes + std::size_t Parse(std::vector const & memory, std::size_t const pos); + }; } \ No newline at end of file diff --git a/include/execute/bytecode.hpp b/include/execute/bytecode.hpp index f09d639..f52bd7f 100644 --- a/include/execute/bytecode.hpp +++ b/include/execute/bytecode.hpp @@ -3,41 +3,41 @@ namespace Execute { - enum class InstructionByte : std::uint8_t - { - NOOP = 0, - /* Integer functions */ - ADD_INTEGER, - SUBTRACT_INTEGER, - DIVIDE_INTEGER, - MULTIPLY_INTEGER, - SHIFT_LEFT_INTEGER, - SHIFT_RIGHT_INTEGER, - SET_INTEGER, - /* Control flow */ - JUMP, - INTERRUPT, - CALL, - RETURN, - EXIT, - LESS_THAN_INTEGER, - GREATER_THAN_INTEGER, - EQUALS_INTEGER, - /* Memory */ - POP_INTEGER, - PUSH_INTEGER, - /* Values */ - IMMEDIATE_INTEGER, - REGISTER, - MEMORY_OP, - LABEL, - }; + enum class InstructionByte : std::uint8_t + { + NOOP = 0, + /* Integer functions */ + ADD_INTEGER, + SUBTRACT_INTEGER, + DIVIDE_INTEGER, + MULTIPLY_INTEGER, + SHIFT_LEFT_INTEGER, + SHIFT_RIGHT_INTEGER, + SET_INTEGER, + /* Control flow */ + JUMP, + INTERRUPT, + CALL, + RETURN, + EXIT, + LESS_THAN_INTEGER, + GREATER_THAN_INTEGER, + EQUALS_INTEGER, + /* Memory */ + POP_INTEGER, + PUSH_INTEGER, + /* Values */ + IMMEDIATE_INTEGER, + REGISTER, + MEMORY_OP, + LABEL, + }; - enum class RegisterByte : std::uint8_t - { - A = 1, - B, - C, - D - }; + enum class RegisterByte : std::uint8_t + { + A = 1, + B, + C, + D + }; } \ No newline at end of file diff --git a/include/execute/error.hpp b/include/execute/error.hpp index 012950e..4d02470 100644 --- a/include/execute/error.hpp +++ b/include/execute/error.hpp @@ -3,48 +3,40 @@ namespace Execute { - class RuntimeError - { - protected: - std::string message; - std::size_t byteLocation; + class RuntimeError { + protected: + std::string message; + std::size_t byteLocation; - public: - std::string const & GetMessage() const; + public: + std::string const & GetMessage() const; - RuntimeError(); - RuntimeError(std::string const & what, std::size_t const byteLocation); - }; + RuntimeError(); + RuntimeError(std::string const & what, std::size_t const byteLocation); + }; - class InterruptIndexOutOfRange : public RuntimeError - { - public: - InterruptIndexOutOfRange(std::size_t const location, int const index); - }; + class InterruptIndexOutOfRange : public RuntimeError { + public: + InterruptIndexOutOfRange(std::size_t const location, int const index); + }; - class AttemptedWriteToImmediate : public RuntimeError - { - public: - AttemptedWriteToImmediate(std::size_t const location); - }; + class AttemptedWriteToImmediate : public RuntimeError { + public: + AttemptedWriteToImmediate(std::size_t const location); + }; - class NonExecutableInstruction : public RuntimeError - { - public: - NonExecutableInstruction(std::size_t const location); - }; + class NonExecutableInstruction : public RuntimeError { + public: + NonExecutableInstruction(std::size_t const location); + }; - class NonArgumentByte : public RuntimeError - { - public: - NonArgumentByte(std::size_t const location); - }; + class NonArgumentByte : public RuntimeError { + public: + NonArgumentByte(std::size_t const location); + }; - class OutOfMemory : public RuntimeError - { - public: - OutOfMemory( - std::size_t const requiredMemorySize, - std::size_t const actualMemorySize); - }; + class OutOfMemory : public RuntimeError { + public: + OutOfMemory(std::size_t const requiredMemorySize, std::size_t const actualMemorySize); + }; } \ No newline at end of file diff --git a/include/execute/interrupts.hpp b/include/execute/interrupts.hpp index 5dbde01..4931bf2 100644 --- a/include/execute/interrupts.hpp +++ b/include/execute/interrupts.hpp @@ -5,8 +5,5 @@ namespace Execute { - void ExecuteInterrupt( - int const id, - Execute::Registers & registers, - std::vector & memory); + void ExecuteInterrupt(int const id, Execute::Registers & registers, std::vector & memory); } \ No newline at end of file diff --git a/include/execute/registers.hpp b/include/execute/registers.hpp index a883039..b14a531 100644 --- a/include/execute/registers.hpp +++ b/include/execute/registers.hpp @@ -3,12 +3,12 @@ namespace Execute { - struct Registers - { - int A, B, C, D; - std::size_t programCounter; - std::size_t stackPointer; + struct Registers + { + int A, B, C, D; + std::size_t programCounter; + std::size_t stackPointer; - // TODO status registers? - }; + // TODO status registers? + }; } diff --git a/include/execute/state.hpp b/include/execute/state.hpp index 2cf2154..4fc67bf 100644 --- a/include/execute/state.hpp +++ b/include/execute/state.hpp @@ -5,13 +5,13 @@ namespace Execute { - struct State - { - bool terminated; - Registers registers; - std::vector memory; + struct State + { + bool terminated; + Registers registers; + std::vector memory; - void PushToStack(int const value); - int PopFromStack(); - }; + void PushToStack(int const value); + int PopFromStack(); + }; } \ No newline at end of file diff --git a/include/execute/virtualmachine.hpp b/include/execute/virtualmachine.hpp index 2f6ffb8..f215e19 100644 --- a/include/execute/virtualmachine.hpp +++ b/include/execute/virtualmachine.hpp @@ -6,42 +6,35 @@ namespace Execute { - class VirtualMachine - { - private: - State state; + class VirtualMachine { + private: + State state; - void DoArithmatic( - InstructionByte const instruction, - std::array & arguments); - void SetInteger(std::array & arguments); - void ExecuteJump(std::array & arguments); - void ExecuteInterrupt(std::array & arguments); - void ExecuteCall( - std::array & arguments, - std::size_t const returnByte); - void ExecuteReturn(); - void DoBooleanLogic( - InstructionByte const instruction, - std::array & arguments, - std::size_t const nextInstruction); - void ExecutePop(std::array & arguments); - void ExecutePush(std::array & arguments); + void DoArithmatic(InstructionByte const instruction, std::array & arguments); + void SetInteger(std::array & arguments); + void ExecuteJump(std::array & arguments); + void ExecuteInterrupt(std::array & arguments); + void ExecuteCall(std::array & arguments, std::size_t const returnByte); + void ExecuteReturn(); + void DoBooleanLogic( + InstructionByte const instruction, + std::array & arguments, + std::size_t const nextInstruction); + void ExecutePop(std::array & arguments); + void ExecutePush(std::array & arguments); - void Step(); + void Step(); - public: - void Run(); - void SingleStep(); + public: + void Run(); + void SingleStep(); - void SetMemorySize(std::size_t const size); - void LoadCode( - std::vector const & byteCode, - bool const printDecodedBytes); + void SetMemorySize(std::size_t const size); + void LoadCode(std::vector const & byteCode, bool const printDecodedBytes); - State const & GetState() const; - Execute::InstructionByte GetCurrentInstruction() const; + State const & GetState() const; + Execute::InstructionByte GetCurrentInstruction() const; - bool IsTerminated() const; - }; + bool IsTerminated() const; + }; } \ No newline at end of file diff --git a/include/preprocessor/preprocessor.hpp b/include/preprocessor/preprocessor.hpp index 880b8d5..3a0c2a0 100644 --- a/include/preprocessor/preprocessor.hpp +++ b/include/preprocessor/preprocessor.hpp @@ -2,20 +2,17 @@ #include #include -class Preprocessor -{ +class Preprocessor { private: - std::vector substitutionIdentifiers; - std::vector substitutionValues; + std::vector substitutionIdentifiers; + std::vector substitutionValues; - void extractComment(std::string & line, - std::size_t const lineNumber, - std::size_t const lineColumn); + void extractComment(std::string & line, std::size_t const lineNumber, std::size_t const lineColumn); - void processLine(std::string & line, std::size_t const lineNumber); + void processLine(std::string & line, std::size_t const lineNumber); public: - void process(std::vector & lines); + void process(std::vector & lines); - void printSubstitutions() const; + void printSubstitutions() const; }; \ No newline at end of file diff --git a/include/token/errors.hpp b/include/token/errors.hpp index 46d9d73..0ccde97 100644 --- a/include/token/errors.hpp +++ b/include/token/errors.hpp @@ -4,10 +4,10 @@ namespace Token { - struct TokenizationError : public std::exception - { - Token errorToken; - std::string errorMsg; - TokenizationError(Token const & token, std::string const & msg); - }; + struct TokenizationError : public std::exception + { + Token errorToken; + std::string errorMsg; + TokenizationError(Token const & token, std::string const & msg); + }; } \ No newline at end of file diff --git a/include/token/operandtype.hpp b/include/token/operandtype.hpp index 3bdea6e..fbf5725 100644 --- a/include/token/operandtype.hpp +++ b/include/token/operandtype.hpp @@ -3,27 +3,27 @@ namespace Token { - enum class OperandType : int - { - Unknown = -1, - AddInteger = 0, - SubtractInteger, - DivideInteger, - MultiplyInteger, - ShiftIntegerLeft, - ShiftIntegerRight, - Jump, - CallFunction, - ReturnFromFunction, - ExitProgram, - LessThanInteger, - GreaterThanInteger, - EqualInteger, - SetInteger, - Interrupt, - PushInteger, - PopInteger - }; + enum class OperandType : int + { + Unknown = -1, + AddInteger = 0, + SubtractInteger, + DivideInteger, + MultiplyInteger, + ShiftIntegerLeft, + ShiftIntegerRight, + Jump, + CallFunction, + ReturnFromFunction, + ExitProgram, + LessThanInteger, + GreaterThanInteger, + EqualInteger, + SetInteger, + Interrupt, + PushInteger, + PopInteger + }; - OperandType GetOperandType(std::string const & op); + OperandType GetOperandType(std::string const & op); } \ No newline at end of file diff --git a/include/token/registertype.hpp b/include/token/registertype.hpp index 354ea2b..bebda7d 100644 --- a/include/token/registertype.hpp +++ b/include/token/registertype.hpp @@ -3,14 +3,14 @@ namespace Token { - enum class RegisterType - { - Unknown = -1, - A = 0, - B, - C, - D - }; + enum class RegisterType + { + Unknown = -1, + A = 0, + B, + C, + D + }; - RegisterType GetRegisterType(std::string const & reg); + RegisterType GetRegisterType(std::string const & reg); } \ No newline at end of file diff --git a/include/token/token.hpp b/include/token/token.hpp index 07e721b..506d9dd 100644 --- a/include/token/token.hpp +++ b/include/token/token.hpp @@ -7,47 +7,58 @@ namespace Token { - enum class TokenValueType - { - None = 0, - Integer, - Operand, - Register, - String - }; + enum class TokenValueType + { + None = 0, + Integer, + Operand, + Register, + String + }; - struct Token - { - private: - Token(TokenType type, bool validness, int const lineNumber, int const lineColumn); - Token(TokenType type, std::string const & string, bool validness, int const lineNumber, int const lineColumn); - Token(TokenType type, int value, bool validness, int const lineNumber, int const lineColumn); - Token(TokenType type, RegisterType const registerType, bool validness, int const lineNumber, int const lineColumn); - Token(TokenType type, OperandType const OperandType, bool validness, int const lineNumber, int const lineColumn); + struct Token + { + private: + Token(TokenType type, bool validness, int const lineNumber, int const lineColumn); + Token(TokenType type, std::string const & string, bool validness, int const lineNumber, int const lineColumn); + Token(TokenType type, int value, bool validness, int const lineNumber, int const lineColumn); + Token( + TokenType type, + RegisterType const registerType, + bool validness, + int const lineNumber, + int const lineColumn); + Token( + TokenType type, + OperandType const OperandType, + bool validness, + int const lineNumber, + int const lineColumn); - public: - int const lineNumber; - int const lineColumn; - TokenType type; - TokenValueType const valueType; - bool isValid; - std::variant data; - std::string errorMessage; + public: + int const lineNumber; + int const lineColumn; + TokenType type; + TokenValueType const valueType; + bool isValid; + std::variant data; + std::string errorMessage; - Token(Token const & other); + Token(Token const & other); - static Token CreateEmptyToken(int const lineNumber, int const lineColumn); - static Token CreateErrorToken(std::string const & message, TokenType const type, int const lineNumber, int const lineColumn); - static Token CreateStatementEndToken(int const lineNumber, int const lineColumn); - static Token CreateLabelDefinitionToken(std::string const & string, int const lineNumber, int const lineColumn); - static Token CreateLabelArgumentToken(std::string const & string, int const lineNumber, int const lineColumn); - static Token CreateImmediateValueToken(int const value, int const lineNumber, int const lineColumn); - static Token CreateRegisterToken(RegisterType const registerType, int const lineNumber, int const lineColumn); - static Token CreateOperandToken(OperandType const operandType, int const lineNumber, int const lineColumn); - static Token CreateMemoryToken(RegisterType const registerType, int const lineNumber, int const lineColumn); - static Token CreateMemoryToken(int const value, int const lineNumber, int const lineColumn); + static Token CreateEmptyToken(int const lineNumber, int const lineColumn); + static Token + CreateErrorToken(std::string const & message, TokenType const type, int const lineNumber, int const lineColumn); + static Token CreateStatementEndToken(int const lineNumber, int const lineColumn); + static Token CreateLabelDefinitionToken(std::string const & string, int const lineNumber, int const lineColumn); + static Token CreateLabelArgumentToken(std::string const & string, int const lineNumber, int const lineColumn); + static Token CreateImmediateValueToken(int const value, int const lineNumber, int const lineColumn); + static Token CreateRegisterToken(RegisterType const registerType, int const lineNumber, int const lineColumn); + static Token CreateOperandToken(OperandType const operandType, int const lineNumber, int const lineColumn); + static Token CreateMemoryToken(RegisterType const registerType, int const lineNumber, int const lineColumn); + static Token CreateMemoryToken(int const value, int const lineNumber, int const lineColumn); - std::string GetName() const; - void Print() const; - }; + std::string GetName() const; + void Print() const; + }; } diff --git a/include/token/tokenizer.hpp b/include/token/tokenizer.hpp index f09cfc9..51a501e 100644 --- a/include/token/tokenizer.hpp +++ b/include/token/tokenizer.hpp @@ -5,19 +5,13 @@ namespace Token { - class Tokenizer - { - private: - // Argument for string should never be of length zero - Token ExtractToken( - std::string const & string, - std::size_t const lineNumber, - std::size_t const lineColumn) const; + class Tokenizer { + private: + // Argument for string should never be of length zero + Token + ExtractToken(std::string const & string, std::size_t const lineNumber, std::size_t const lineColumn) const; - public: - void Tokenize( - std::string const & line, - std::size_t const lineNumber, - std::vector & tokens); - }; + public: + void Tokenize(std::string const & line, std::size_t const lineNumber, std::vector & tokens); + }; } \ No newline at end of file diff --git a/include/token/tokentype.hpp b/include/token/tokentype.hpp index 2d9804c..c2d9163 100644 --- a/include/token/tokentype.hpp +++ b/include/token/tokentype.hpp @@ -2,15 +2,15 @@ namespace Token { - enum class TokenType - { - Unknown = -1, - Operand = 0, - ImmediateInteger, - Register, - StatementEnd, - LabelDefinition, - LabelArgument, - Memory - }; + enum class TokenType + { + Unknown = -1, + Operand = 0, + ImmediateInteger, + Register, + StatementEnd, + LabelDefinition, + LabelArgument, + Memory + }; } \ No newline at end of file diff --git a/include/utils.hpp b/include/utils.hpp index 3504c4c..df837e7 100644 --- a/include/utils.hpp +++ b/include/utils.hpp @@ -6,25 +6,18 @@ namespace Utils { - bool isWhitespaceCharacter(char const c); + bool isWhitespaceCharacter(char const c); - // Returns nullopt in case the value is missing its terminator character - std::optional getValueSurroundedBy( - std::string const & src, - std::size_t const pos, - char const surroundingCharacter); + // Returns nullopt in case the value is missing its terminator character + std::optional + getValueSurroundedBy(std::string const & src, std::size_t const pos, char const surroundingCharacter); - std::string getValueSurroundedByWhitespace( - std::string const & src, - std::size_t const pos); + std::string getValueSurroundedByWhitespace(std::string const & src, std::size_t const pos); - namespace Bytes - { - void Write( - int const value, - std::vector & vec, - std::size_t const pos); + namespace Bytes + { + void Write(int const value, std::vector & vec, std::size_t const pos); - int Read(std::vector const & vec, std::size_t const pos); - } + int Read(std::vector const & vec, std::size_t const pos); + } } \ No newline at end of file diff --git a/include/wassembler.hpp b/include/wassembler.hpp index d810d88..ebe1607 100644 --- a/include/wassembler.hpp +++ b/include/wassembler.hpp @@ -3,42 +3,33 @@ #include #include -class Wassembler -{ +class Wassembler { private: - Execute::VirtualMachine vm; - bool printSubstitutions; - bool printTokens; - bool printTranslatedBytes; + Execute::VirtualMachine vm; + bool printSubstitutions; + bool printTokens; + bool printTranslatedBytes; - bool LoadTextFile( - std::string const & filePath, - std::vector & lines) const; - bool Preprocess(std::vector & lines) const; - bool Tokenize( - std::vector const & lines, - std::vector & tokens) const; - bool CompileToBytes( - std::vector const & tokens, - std::vector const & lines, - std::vector & bytes) const; - void ExecuteCode(std::vector const & bytes); + bool LoadTextFile(std::string const & filePath, std::vector & lines) const; + bool Preprocess(std::vector & lines) const; + bool Tokenize(std::vector const & lines, std::vector & tokens) const; + bool CompileToBytes( + std::vector const & tokens, + std::vector const & lines, + std::vector & bytes) const; + void ExecuteCode(std::vector const & bytes); - bool CompileFile( - std::string const & filePath, - std::vector & bytes) const; + bool CompileFile(std::string const & filePath, std::vector & bytes) const; public: - void SetMemorySize(unsigned const size); + void SetMemorySize(unsigned const size); - void EnableSubstitutionsLogging(); - void EnableTokensLogging(); - void EnableByteTranslationLogging(); + void EnableSubstitutionsLogging(); + void EnableTokensLogging(); + void EnableByteTranslationLogging(); - bool CompileAndRun(std::string const & filePath); - bool CompileToFile( - std::string const & inputFilePath, - std::string const & outputFilePath); + bool CompileAndRun(std::string const & filePath); + bool CompileToFile(std::string const & inputFilePath, std::string const & outputFilePath); - Wassembler() = default; + Wassembler() = default; }; \ No newline at end of file diff --git a/makefile b/makefile index 3dce55e..65936b9 100644 --- a/makefile +++ b/makefile @@ -1,6 +1,6 @@ CC = g++ -CFLAGS = -g -std=c++17 -Wall -Iinclude #-Werror -LFLAGS = #-lsfml-graphics -lsfml-window -lsfml-system +CFLAGS = -g -std=c++17 -Wall -Wextra -Iinclude +LFLAGS = CPPS = $(shell find src/ -name '*.cpp') OBJS = $(patsubst src/%.cpp, build/%.o, ${CPPS}) diff --git a/src/compile/compiler.cpp b/src/compile/compiler.cpp index f8415fb..44ce9ef 100644 --- a/src/compile/compiler.cpp +++ b/src/compile/compiler.cpp @@ -6,428 +6,417 @@ namespace Compile { - int GetRequiredNumberOfArguments(Token::OperandType const type) - { - switch (type) - { - case Token::OperandType::AddInteger: - case Token::OperandType::SubtractInteger: - case Token::OperandType::DivideInteger: - case Token::OperandType::MultiplyInteger: - case Token::OperandType::ShiftIntegerLeft: - case Token::OperandType::ShiftIntegerRight: - return 3; + int GetRequiredNumberOfArguments(Token::OperandType const type) + { + switch(type) + { + case Token::OperandType::AddInteger: + case Token::OperandType::SubtractInteger: + case Token::OperandType::DivideInteger: + case Token::OperandType::MultiplyInteger: + case Token::OperandType::ShiftIntegerLeft: + case Token::OperandType::ShiftIntegerRight: + return 3; - case Token::OperandType::LessThanInteger: - case Token::OperandType::GreaterThanInteger: - case Token::OperandType::EqualInteger: - case Token::OperandType::SetInteger: - return 2; + case Token::OperandType::LessThanInteger: + case Token::OperandType::GreaterThanInteger: + case Token::OperandType::EqualInteger: + case Token::OperandType::SetInteger: + return 2; - case Token::OperandType::Jump: - case Token::OperandType::CallFunction: - case Token::OperandType::Interrupt: - case Token::OperandType::PushInteger: - case Token::OperandType::PopInteger: - return 1; + case Token::OperandType::Jump: + case Token::OperandType::CallFunction: + case Token::OperandType::Interrupt: + case Token::OperandType::PushInteger: + case Token::OperandType::PopInteger: + return 1; - default: - std::printf("WARNING: returning default argument length of 0 for operand type %i\n", static_cast(type)); - case Token::OperandType::ReturnFromFunction: - case Token::OperandType::ExitProgram: - return 0; - } - } + default: + std::printf( + "WARNING: returning default argument length of 0 for operand type %i\n", + static_cast(type)); + case Token::OperandType::ReturnFromFunction: + case Token::OperandType::ExitProgram: + return 0; + } + } - bool IsArgumentToken(Token::Token const & t) - { - return - t.type == Token::TokenType::ImmediateInteger || - t.type == Token::TokenType::Register || - t.type == Token::TokenType::LabelArgument || - t.type == Token::TokenType::Memory; - } + bool IsArgumentToken(Token::Token const & t) + { + return t.type == Token::TokenType::ImmediateInteger || t.type == Token::TokenType::Register + || t.type == Token::TokenType::LabelArgument || t.type == Token::TokenType::Memory; + } - bool IsReadableToken(Token::Token const & t) - { - return - t.type == Token::TokenType::ImmediateInteger || - t.type == Token::TokenType::Register || - t.type == Token::TokenType::Memory; - } + bool IsReadableToken(Token::Token const & t) + { + return t.type == Token::TokenType::ImmediateInteger || t.type == Token::TokenType::Register + || t.type == Token::TokenType::Memory; + } - bool IsWriteableToken(Token::Token const & t) - { - return - t.type == Token::TokenType::Register || - t.type == Token::TokenType::Memory; - } + bool IsWriteableToken(Token::Token const & t) + { + return t.type == Token::TokenType::Register || t.type == Token::TokenType::Memory; + } - void ValidateArguments( - std::vector const & tokens, - std::size_t const operandIndex) - { - auto const operandType = std::get(tokens[operandIndex].data); - switch(operandType) - { - // 2 Read values + 1 write value - case Token::OperandType::AddInteger: - case Token::OperandType::SubtractInteger: - case Token::OperandType::DivideInteger: - case Token::OperandType::MultiplyInteger: - case Token::OperandType::ShiftIntegerLeft: - case Token::OperandType::ShiftIntegerRight: - if (!IsReadableToken(tokens[operandIndex + 1])) - { - throw CompilationError::CreateExpectedImmediateOrRegisterOrMemory(tokens[operandIndex + 1]); - } - if (!IsReadableToken(tokens[operandIndex + 2])) - { - throw CompilationError::CreateExpectedImmediateOrRegisterOrMemory(tokens[operandIndex + 2]); - } - if (!IsWriteableToken(tokens[operandIndex + 3])) - { - throw CompilationError::CreateExpectedRegisterOrMemoryError(tokens[operandIndex + 3]); - } - break; + void ValidateArguments(std::vector const & tokens, std::size_t const operandIndex) + { + auto const operandType = std::get(tokens[operandIndex].data); + switch(operandType) + { + // 2 Read values + 1 write value + case Token::OperandType::AddInteger: + case Token::OperandType::SubtractInteger: + case Token::OperandType::DivideInteger: + case Token::OperandType::MultiplyInteger: + case Token::OperandType::ShiftIntegerLeft: + case Token::OperandType::ShiftIntegerRight: + if(!IsReadableToken(tokens[operandIndex + 1])) + { + throw CompilationError::CreateExpectedImmediateOrRegisterOrMemory(tokens[operandIndex + 1]); + } + if(!IsReadableToken(tokens[operandIndex + 2])) + { + throw CompilationError::CreateExpectedImmediateOrRegisterOrMemory(tokens[operandIndex + 2]); + } + if(!IsWriteableToken(tokens[operandIndex + 3])) + { + throw CompilationError::CreateExpectedRegisterOrMemoryError(tokens[operandIndex + 3]); + } + break; - // 2 Read values - case Token::OperandType::LessThanInteger: - case Token::OperandType::GreaterThanInteger: - case Token::OperandType::EqualInteger: - case Token::OperandType::SetInteger: - if (!IsReadableToken(tokens[operandIndex + 1])) - { - throw CompilationError::CreateExpectedImmediateOrRegisterOrMemory(tokens[operandIndex + 1]); - } - if (!IsReadableToken(tokens[operandIndex + 2])) - { - throw CompilationError::CreateExpectedImmediateOrRegisterOrMemory(tokens[operandIndex + 2]); - } - break; + // 2 Read values + case Token::OperandType::LessThanInteger: + case Token::OperandType::GreaterThanInteger: + case Token::OperandType::EqualInteger: + case Token::OperandType::SetInteger: + if(!IsReadableToken(tokens[operandIndex + 1])) + { + throw CompilationError::CreateExpectedImmediateOrRegisterOrMemory(tokens[operandIndex + 1]); + } + if(!IsReadableToken(tokens[operandIndex + 2])) + { + throw CompilationError::CreateExpectedImmediateOrRegisterOrMemory(tokens[operandIndex + 2]); + } + break; - // 1 Label value - case Token::OperandType::Jump: - case Token::OperandType::CallFunction: - if (tokens[operandIndex + 1].type != Token::TokenType::LabelArgument) - { - throw CompilationError::CreateExpectedLabelError(tokens[operandIndex + 1]); - } - break; + // 1 Label value + case Token::OperandType::Jump: + case Token::OperandType::CallFunction: + if(tokens[operandIndex + 1].type != Token::TokenType::LabelArgument) + { + throw CompilationError::CreateExpectedLabelError(tokens[operandIndex + 1]); + } + break; - // 1 Read value - case Token::OperandType::Interrupt: - case Token::OperandType::PushInteger: - if (!IsReadableToken(tokens[operandIndex + 1])) - { - throw CompilationError::CreateExpectedImmediateOrRegisterOrMemory(tokens[operandIndex + 1]); - } - break; + // 1 Read value + case Token::OperandType::Interrupt: + case Token::OperandType::PushInteger: + if(!IsReadableToken(tokens[operandIndex + 1])) + { + throw CompilationError::CreateExpectedImmediateOrRegisterOrMemory(tokens[operandIndex + 1]); + } + break; - // 1 Write value - case Token::OperandType::PopInteger: - if (!IsWriteableToken(tokens[operandIndex + 1])) - { - throw CompilationError::CreateExpectedRegisterOrMemoryError(tokens[operandIndex + 1]); - } - break; + // 1 Write value + case Token::OperandType::PopInteger: + if(!IsWriteableToken(tokens[operandIndex + 1])) + { + throw CompilationError::CreateExpectedRegisterOrMemoryError(tokens[operandIndex + 1]); + } + break; - default: - throw std::runtime_error("Unimplemented operandType case in ValidateArguments"); - } - } + default: + throw std::runtime_error("Unimplemented operandType case in ValidateArguments"); + } + } - Execute::RegisterByte GetByteCodeRegister(Token::RegisterType const v) - { - switch(v) - { - case Token::RegisterType::A: - return Execute::RegisterByte::A; + Execute::RegisterByte GetByteCodeRegister(Token::RegisterType const v) + { + switch(v) + { + case Token::RegisterType::A: + return Execute::RegisterByte::A; - case Token::RegisterType::B: - return Execute::RegisterByte::B; + case Token::RegisterType::B: + return Execute::RegisterByte::B; - case Token::RegisterType::C: - return Execute::RegisterByte::C; + case Token::RegisterType::C: + return Execute::RegisterByte::C; - case Token::RegisterType::D: - return Execute::RegisterByte::D; + case Token::RegisterType::D: + return Execute::RegisterByte::D; - default: - throw std::runtime_error("Unhandled register type in GetByteCodeRegister"); - } - } + default: + throw std::runtime_error("Unhandled register type in GetByteCodeRegister"); + } + } - void Compiler::InsertAsBytes( - Token::Token const & token, - std::vector & bytes) - { - switch(token.type) - { - case Token::TokenType::ImmediateInteger: - bytes.push_back(static_cast(Execute::InstructionByte::IMMEDIATE_INTEGER)); - { - int value = std::get(token.data); - auto const insertionIndex = bytes.size(); - bytes.resize(bytes.size() + 4); - Utils::Bytes::Write(value, bytes, insertionIndex); - } - break; + void Compiler::InsertAsBytes(Token::Token const & token, std::vector & bytes) + { + switch(token.type) + { + case Token::TokenType::ImmediateInteger: + bytes.push_back(static_cast(Execute::InstructionByte::IMMEDIATE_INTEGER)); + { + int value = std::get(token.data); + auto const insertionIndex = bytes.size(); + bytes.resize(bytes.size() + 4); + Utils::Bytes::Write(value, bytes, insertionIndex); + } + break; - case Token::TokenType::Operand: - { - switch(std::get(token.data)) - { - case Token::OperandType::AddInteger: - bytes.push_back(static_cast(Execute::InstructionByte::ADD_INTEGER)); - break; + case Token::TokenType::Operand: + { + switch(std::get(token.data)) + { + case Token::OperandType::AddInteger: + bytes.push_back(static_cast(Execute::InstructionByte::ADD_INTEGER)); + break; - case Token::OperandType::SubtractInteger: - bytes.push_back(static_cast(Execute::InstructionByte::SUBTRACT_INTEGER)); - break; + case Token::OperandType::SubtractInteger: + bytes.push_back(static_cast(Execute::InstructionByte::SUBTRACT_INTEGER)); + break; - case Token::OperandType::DivideInteger: - bytes.push_back(static_cast(Execute::InstructionByte::DIVIDE_INTEGER)); - break; + case Token::OperandType::DivideInteger: + bytes.push_back(static_cast(Execute::InstructionByte::DIVIDE_INTEGER)); + break; - case Token::OperandType::MultiplyInteger: - bytes.push_back(static_cast(Execute::InstructionByte::MULTIPLY_INTEGER)); - break; + case Token::OperandType::MultiplyInteger: + bytes.push_back(static_cast(Execute::InstructionByte::MULTIPLY_INTEGER)); + break; - case Token::OperandType::ShiftIntegerLeft: - bytes.push_back(static_cast(Execute::InstructionByte::SHIFT_LEFT_INTEGER)); - break; + case Token::OperandType::ShiftIntegerLeft: + bytes.push_back(static_cast(Execute::InstructionByte::SHIFT_LEFT_INTEGER)); + break; - case Token::OperandType::ShiftIntegerRight: - bytes.push_back(static_cast(Execute::InstructionByte::SHIFT_RIGHT_INTEGER)); - break; + case Token::OperandType::ShiftIntegerRight: + bytes.push_back(static_cast(Execute::InstructionByte::SHIFT_RIGHT_INTEGER)); + break; - case Token::OperandType::LessThanInteger: - bytes.push_back(static_cast(Execute::InstructionByte::LESS_THAN_INTEGER)); - break; + case Token::OperandType::LessThanInteger: + bytes.push_back(static_cast(Execute::InstructionByte::LESS_THAN_INTEGER)); + break; - case Token::OperandType::GreaterThanInteger: - bytes.push_back(static_cast(Execute::InstructionByte::GREATER_THAN_INTEGER)); - break; + case Token::OperandType::GreaterThanInteger: + bytes.push_back(static_cast(Execute::InstructionByte::GREATER_THAN_INTEGER)); + break; - case Token::OperandType::EqualInteger: - bytes.push_back(static_cast(Execute::InstructionByte::EQUALS_INTEGER)); - break; + case Token::OperandType::EqualInteger: + bytes.push_back(static_cast(Execute::InstructionByte::EQUALS_INTEGER)); + break; - case Token::OperandType::SetInteger: - bytes.push_back(static_cast(Execute::InstructionByte::SET_INTEGER)); - break; + case Token::OperandType::SetInteger: + bytes.push_back(static_cast(Execute::InstructionByte::SET_INTEGER)); + break; - case Token::OperandType::Jump: - bytes.push_back(static_cast(Execute::InstructionByte::JUMP)); - break; + case Token::OperandType::Jump: + bytes.push_back(static_cast(Execute::InstructionByte::JUMP)); + break; - case Token::OperandType::CallFunction: - bytes.push_back(static_cast(Execute::InstructionByte::CALL)); - break; + case Token::OperandType::CallFunction: + bytes.push_back(static_cast(Execute::InstructionByte::CALL)); + break; - case Token::OperandType::Interrupt: - bytes.push_back(static_cast(Execute::InstructionByte::INTERRUPT)); - break; + case Token::OperandType::Interrupt: + bytes.push_back(static_cast(Execute::InstructionByte::INTERRUPT)); + break; - case Token::OperandType::PushInteger: - bytes.push_back(static_cast(Execute::InstructionByte::PUSH_INTEGER)); - break; + case Token::OperandType::PushInteger: + bytes.push_back(static_cast(Execute::InstructionByte::PUSH_INTEGER)); + break; - case Token::OperandType::PopInteger: - bytes.push_back(static_cast(Execute::InstructionByte::POP_INTEGER)); - break; + case Token::OperandType::PopInteger: + bytes.push_back(static_cast(Execute::InstructionByte::POP_INTEGER)); + break; - case Token::OperandType::ReturnFromFunction: - bytes.push_back(static_cast(Execute::InstructionByte::RETURN)); - break; + case Token::OperandType::ReturnFromFunction: + bytes.push_back(static_cast(Execute::InstructionByte::RETURN)); + break; - case Token::OperandType::ExitProgram: - bytes.push_back(static_cast(Execute::InstructionByte::EXIT)); - break; + case Token::OperandType::ExitProgram: + bytes.push_back(static_cast(Execute::InstructionByte::EXIT)); + break; - break; + break; - default: - throw std::runtime_error("Unhandled operand type in InsertAsBytes"); - } - } - break; + default: + throw std::runtime_error("Unhandled operand type in InsertAsBytes"); + } + } + break; - case Token::TokenType::Register: - bytes.push_back(static_cast(Execute::InstructionByte::REGISTER)); - bytes.push_back(static_cast(GetByteCodeRegister(std::get(token.data)))); - break; + case Token::TokenType::Register: + bytes.push_back(static_cast(Execute::InstructionByte::REGISTER)); + bytes.push_back( + static_cast(GetByteCodeRegister(std::get(token.data)))); + break; - case Token::TokenType::StatementEnd: - case Token::TokenType::LabelDefinition: - // NO OP - break; + case Token::TokenType::StatementEnd: + case Token::TokenType::LabelDefinition: + // NO OP + break; - case Token::TokenType::LabelArgument: - { - bytes.push_back(static_cast(Execute::InstructionByte::LABEL)); - auto const & label = std::get(token.data); - auto const findResult = jumpLabelLocations.find(label); - int jumpLocation = 0; - if (findResult == jumpLabelLocations.end()) - { - unresolvedJumpLabels.push_back(std::make_pair(token, bytes.size())); - } - else - { - jumpLocation = findResult->second; - } + case Token::TokenType::LabelArgument: + { + bytes.push_back(static_cast(Execute::InstructionByte::LABEL)); + auto const & label = std::get(token.data); + auto const findResult = jumpLabelLocations.find(label); + int jumpLocation = 0; + if(findResult == jumpLabelLocations.end()) + { + unresolvedJumpLabels.push_back(std::make_pair(token, bytes.size())); + } + else + { + jumpLocation = findResult->second; + } - auto const insertionIndex = bytes.size(); - bytes.resize(bytes.size() + 4); - Utils::Bytes::Write(jumpLocation, bytes, insertionIndex); - } - break; + auto const insertionIndex = bytes.size(); + bytes.resize(bytes.size() + 4); + Utils::Bytes::Write(jumpLocation, bytes, insertionIndex); + } + break; - case Token::TokenType::Memory: - { - bytes.push_back(static_cast(Execute::InstructionByte::MEMORY_OP)); - switch(token.valueType) - { - case Token::TokenValueType::Register: - bytes.push_back(static_cast(Execute::InstructionByte::REGISTER)); - bytes.push_back(static_cast(GetByteCodeRegister(std::get(token.data)))); - break; + case Token::TokenType::Memory: + { + bytes.push_back(static_cast(Execute::InstructionByte::MEMORY_OP)); + switch(token.valueType) + { + case Token::TokenValueType::Register: + bytes.push_back(static_cast(Execute::InstructionByte::REGISTER)); + bytes.push_back( + static_cast(GetByteCodeRegister(std::get(token.data)))); + break; - case Token::TokenValueType::Integer: - bytes.push_back(static_cast(Execute::InstructionByte::IMMEDIATE_INTEGER)); - { - auto const insertionIndex = bytes.size(); - bytes.resize(bytes.size() + 4); - Utils::Bytes::Write(std::get(token.data), bytes, insertionIndex); - } - break; + case Token::TokenValueType::Integer: + bytes.push_back(static_cast(Execute::InstructionByte::IMMEDIATE_INTEGER)); + { + auto const insertionIndex = bytes.size(); + bytes.resize(bytes.size() + 4); + Utils::Bytes::Write(std::get(token.data), bytes, insertionIndex); + } + break; - default: - throw std::runtime_error("Unhandled value type for memory operand in InsertAsBytes"); - } - } - break; + default: + throw std::runtime_error("Unhandled value type for memory operand in InsertAsBytes"); + } + } + break; - default: - throw std::runtime_error("Unhandled token type in InsertAsBytes"); - } - } + default: + throw std::runtime_error("Unhandled token type in InsertAsBytes"); + } + } - bool Compiler::Compile( - std::vector const & tokens, - std::vector & bytes) - { - jumpLabelLocations.clear(); - unresolvedJumpLabels.clear(); + bool Compiler::Compile(std::vector const & tokens, std::vector & bytes) + { + jumpLabelLocations.clear(); + unresolvedJumpLabels.clear(); - enum class State - { - FindOperand, - FindArguments, - FindStatementEnd - }; + enum class State + { + FindOperand, + FindArguments, + FindStatementEnd + }; - State state = State::FindOperand; - Token::OperandType operandType; - unsigned operatorTokenIndex = 0u; - int expectedNumberOfArguments = 0; - for(std::size_t i = 0u; i < tokens.size(); ++i) - { - auto const & token = tokens[i]; - InsertAsBytes(token, bytes); + State state = State::FindOperand; + Token::OperandType operandType; + unsigned operatorTokenIndex = 0u; + int expectedNumberOfArguments = 0; + for(std::size_t i = 0u; i < tokens.size(); ++i) + { + auto const & token = tokens[i]; + InsertAsBytes(token, bytes); - switch(state) - { - case State::FindOperand: - switch(token.type) - { - case Token::TokenType::Operand: - operatorTokenIndex = i; - operandType = std::get(token.data); - expectedNumberOfArguments = GetRequiredNumberOfArguments(operandType); + switch(state) + { + case State::FindOperand: + switch(token.type) + { + case Token::TokenType::Operand: + operatorTokenIndex = i; + operandType = std::get(token.data); + expectedNumberOfArguments = GetRequiredNumberOfArguments(operandType); - if (expectedNumberOfArguments < 1) - { - state = State::FindStatementEnd; - } - else - { - state = State::FindArguments; - } - break; + if(expectedNumberOfArguments < 1) + { + state = State::FindStatementEnd; + } + else + { + state = State::FindArguments; + } + break; - case Token::TokenType::LabelDefinition: - { - auto findResult = jumpLabelLocations.find(std::get(token.data)); - if (findResult == jumpLabelLocations.end()) - { - jumpLabelLocations[std::get(token.data)] = bytes.size(); - } - else - { - throw CompilationError::CreateDuplicateLabelError(token); - } - } - break; + case Token::TokenType::LabelDefinition: + { + auto findResult = jumpLabelLocations.find(std::get(token.data)); + if(findResult == jumpLabelLocations.end()) + { + jumpLabelLocations[std::get(token.data)] = bytes.size(); + } + else + { + throw CompilationError::CreateDuplicateLabelError(token); + } + } + break; - case Token::TokenType::StatementEnd: - // NO OP - break; + case Token::TokenType::StatementEnd: + // NO OP + break; - default: - throw CompilationError::CreateExpectedOperandError(token); - } - break; + default: + throw CompilationError::CreateExpectedOperandError(token); + } + break; - case State::FindArguments: - if (IsArgumentToken(token)) - { - expectedNumberOfArguments -= 1; - if (expectedNumberOfArguments < 1) - { - ValidateArguments(tokens, operatorTokenIndex); - state = State::FindStatementEnd; - } - } - else - { - // TODO Further specify this error? - throw CompilationError::CreateExpectedArgumentError(token); - } - break; + case State::FindArguments: + if(IsArgumentToken(token)) + { + expectedNumberOfArguments -= 1; + if(expectedNumberOfArguments < 1) + { + ValidateArguments(tokens, operatorTokenIndex); + state = State::FindStatementEnd; + } + } + else + { + // TODO Further specify this error? + throw CompilationError::CreateExpectedArgumentError(token); + } + break; - case State::FindStatementEnd: - if (token.type != Token::TokenType::StatementEnd) - { - // TODO Further specify this error? - throw CompilationError::CreateExpectedEndOfStatementError(token); - } - else - { - InsertAsBytes( - token, - bytes); - state = State::FindOperand; - } - break; - } - } + case State::FindStatementEnd: + if(token.type != Token::TokenType::StatementEnd) + { + // TODO Further specify this error? + throw CompilationError::CreateExpectedEndOfStatementError(token); + } + else + { + InsertAsBytes(token, bytes); + state = State::FindOperand; + } + break; + } + } - for(auto const & unresolved : unresolvedJumpLabels) - { - auto const & findResult = jumpLabelLocations.find(std::get(unresolved.first.data)); - if (findResult == jumpLabelLocations.end()) - { - throw CompilationError::CreateNonExistingLabelError(unresolved.first); - } + for(auto const & unresolved: unresolvedJumpLabels) + { + auto const & findResult = jumpLabelLocations.find(std::get(unresolved.first.data)); + if(findResult == jumpLabelLocations.end()) + { + throw CompilationError::CreateNonExistingLabelError(unresolved.first); + } - int const jumpLocation = findResult->second; - auto const index = unresolved.second; - Utils::Bytes::Write(jumpLocation, bytes, index); - } + int const jumpLocation = findResult->second; + auto const index = unresolved.second; + Utils::Bytes::Write(jumpLocation, bytes, index); + } - return true; - } + return true; + } } \ No newline at end of file diff --git a/src/compile/errors.cpp b/src/compile/errors.cpp index 2ebd449..6588664 100644 --- a/src/compile/errors.cpp +++ b/src/compile/errors.cpp @@ -3,73 +3,70 @@ namespace Compile { - CompilationError::CompilationError( - std::string const & message, - Token::Token const & token) - : errorToken(token) - { - errorToken.errorMessage = message; - } + CompilationError::CompilationError(std::string const & message, Token::Token const & token) : errorToken(token) + { + errorToken.errorMessage = message; + } - CompilationError CompilationError::CreateExpectedArgumentError(Token::Token const & token) - { - return CompilationError("Expected an argument", token); - } + CompilationError CompilationError::CreateExpectedArgumentError(Token::Token const & token) + { + return CompilationError("Expected an argument", token); + } - CompilationError CompilationError::CreateExpectedLabelError(Token::Token const & token) - { - return CompilationError("Expected a label", token); - } + CompilationError CompilationError::CreateExpectedLabelError(Token::Token const & token) + { + return CompilationError("Expected a label", token); + } - CompilationError CompilationError::CreateExpectedImmediateError(Token::Token const & token) - { - return CompilationError("Expected an immediate value", token); - } + CompilationError CompilationError::CreateExpectedImmediateError(Token::Token const & token) + { + return CompilationError("Expected an immediate value", token); + } - CompilationError CompilationError::CreateExpectedImmediateOrRegisterOrMemory(Token::Token const & token) - { - return CompilationError("Expected an immediate value, a register or a memory location", token); - } + CompilationError CompilationError::CreateExpectedImmediateOrRegisterOrMemory(Token::Token const & token) + { + return CompilationError("Expected an immediate value, a register or a memory location", token); + } - CompilationError CompilationError::CreateExpectedRegisterError(Token::Token const & token) - { - return CompilationError("Expected a register", token); - } + CompilationError CompilationError::CreateExpectedRegisterError(Token::Token const & token) + { + return CompilationError("Expected a register", token); + } - CompilationError CompilationError::CreateExpectedRegisterOrMemoryError(Token::Token const & token) - { - return CompilationError("Expected a register or a memory location", token); - } + CompilationError CompilationError::CreateExpectedRegisterOrMemoryError(Token::Token const & token) + { + return CompilationError("Expected a register or a memory location", token); + } - CompilationError CompilationError::CreateExpectedOperandError(Token::Token const & token) - { - return CompilationError("Expected an operand", token); - } + CompilationError CompilationError::CreateExpectedOperandError(Token::Token const & token) + { + return CompilationError("Expected an operand", token); + } - CompilationError CompilationError::CreateTooManyArgumentsError(Token::Token const & token) - { - return CompilationError("Too many arguments for operand", token); - } + CompilationError CompilationError::CreateTooManyArgumentsError(Token::Token const & token) + { + return CompilationError("Too many arguments for operand", token); + } - CompilationError CompilationError::CreateTooFewArgumentsError(Token::Token const & token) - { - return CompilationError("Too few arguments for operand", token); - } + CompilationError CompilationError::CreateTooFewArgumentsError(Token::Token const & token) + { + return CompilationError("Too few arguments for operand", token); + } - CompilationError CompilationError::CreateExpectedEndOfStatementError(Token::Token const & token) - { - std::stringstream ss; - ss << "Expected end of statement (;), but got " << token.GetName() << " instead"; - return CompilationError(ss.str(), token); - } + CompilationError CompilationError::CreateExpectedEndOfStatementError(Token::Token const & token) + { + std::stringstream ss; + ss << "Expected end of statement (;), but got " << token.GetName() << " instead"; + return CompilationError(ss.str(), token); + } - CompilationError CompilationError::CreateDuplicateLabelError(Token::Token const & token) - { - return CompilationError("Duplicate label definition", token); - } + CompilationError CompilationError::CreateDuplicateLabelError(Token::Token const & token) + { + return CompilationError("Duplicate label definition", token); + } - CompilationError CompilationError::CreateNonExistingLabelError(Token::Token const & token) - { - return CompilationError("Jumping to non existing label", token); - } + CompilationError CompilationError::CreateNonExistingLabelError(Token::Token const & token) + { + return CompilationError("Jumping to non existing label", token); + } } \ No newline at end of file diff --git a/src/execute/argumentvalue.cpp b/src/execute/argumentvalue.cpp index bd3cb36..4899d8a 100644 --- a/src/execute/argumentvalue.cpp +++ b/src/execute/argumentvalue.cpp @@ -3,142 +3,140 @@ namespace Execute { - int & ArgumentValue::GetRegister(State & state) const - { - switch(std::get(data)) - { - case RegisterByte::A: - return state.registers.A; + int & ArgumentValue::GetRegister(State & state) const + { + switch(std::get(data)) + { + case RegisterByte::A: + return state.registers.A; - case RegisterByte::B: - return state.registers.B; + case RegisterByte::B: + return state.registers.B; - case RegisterByte::C: - return state.registers.C; + case RegisterByte::C: + return state.registers.C; - case RegisterByte::D: - return state.registers.D; + case RegisterByte::D: + return state.registers.D; - default: - throw std::runtime_error("Unhandled register byte in GetRegister"); - } - } + default: + throw std::runtime_error("Unhandled register byte in GetRegister"); + } + } - std::uint8_t * ArgumentValue::GetMemory(State & state) const - { - switch (memoryValueType) - { - case ArgumentType::Immediate: - return &(state.memory[std::get(data)]); + std::uint8_t * ArgumentValue::GetMemory(State & state) const + { + switch(memoryValueType) + { + case ArgumentType::Immediate: + return &(state.memory[std::get(data)]); - case ArgumentType::Register: - return &(state.memory[GetRegister(state)]); + case ArgumentType::Register: + return &(state.memory[GetRegister(state)]); - default: - throw std::runtime_error("Unhandled argument type in GetMemory"); - } - } + default: + throw std::runtime_error("Unhandled argument type in GetMemory"); + } + } - void ArgumentValue::Write(int const value, State & state) const - { - if (type == ArgumentType::Immediate) - { - throw AttemptedWriteToImmediate(state.registers.programCounter); - } + void ArgumentValue::Write(int const value, State & state) const + { + if(type == ArgumentType::Immediate) + { + throw AttemptedWriteToImmediate(state.registers.programCounter); + } - switch(type) - { - case ArgumentType::Memory: - { - auto * ptr = GetMemory(state); - *ptr = value & 0xFF; - *(++ptr) = (value >> 8) & 0xFF; - *(++ptr) = (value >> 16) & 0xFF; - *(++ptr) = (value >> 24) & 0xFF; - } - break; + switch(type) + { + case ArgumentType::Memory: + { + auto * ptr = GetMemory(state); + *ptr = value & 0xFF; + *(++ptr) = (value >> 8) & 0xFF; + *(++ptr) = (value >> 16) & 0xFF; + *(++ptr) = (value >> 24) & 0xFF; + } + break; - case ArgumentType::Register: - GetRegister(state) = value; - break; + case ArgumentType::Register: + GetRegister(state) = value; + break; - default: - throw std::runtime_error("Unhandled argument type in Write"); - } - } + default: + throw std::runtime_error("Unhandled argument type in Write"); + } + } - int ArgumentValue::Read(State & state) const - { - switch(type) - { - case ArgumentType::Immediate: - return std::get(data); + int ArgumentValue::Read(State & state) const + { + switch(type) + { + case ArgumentType::Immediate: + return std::get(data); - case ArgumentType::Memory: - { - int result = 0; - auto * ptr = GetMemory(state); - result |= static_cast(*ptr); - result |= static_cast(*(++ptr)) << 8; - result |= static_cast(*(++ptr)) << 16; - result |= static_cast(*(++ptr)) << 24; - } - break; + case ArgumentType::Memory: + { + int result = 0; + auto * ptr = GetMemory(state); + result |= static_cast(*ptr); + result |= static_cast(*(++ptr)) << 8; + result |= static_cast(*(++ptr)) << 16; + result |= static_cast(*(++ptr)) << 24; + } + break; - case ArgumentType::Register: - return GetRegister(state); + case ArgumentType::Register: + return GetRegister(state); - default: - throw std::runtime_error("Unhandled argument type in Read"); - } - } + default: + throw std::runtime_error("Unhandled argument type in Read"); + } + } - // Returns the size of the argument in bytes - std::size_t ArgumentValue::Parse( - std::vector const & memory, - std::size_t const pos) - { - InstructionByte const valueByte = static_cast(memory[pos]); - switch(valueByte) - { - case InstructionByte::IMMEDIATE_INTEGER: - case InstructionByte::LABEL: - type = ArgumentType::Immediate; - data = Utils::Bytes::Read(memory, pos + 1); - return 5; + // Returns the size of the argument in bytes + std::size_t ArgumentValue::Parse(std::vector const & memory, std::size_t const pos) + { + InstructionByte const valueByte = static_cast(memory[pos]); + switch(valueByte) + { + case InstructionByte::IMMEDIATE_INTEGER: + case InstructionByte::LABEL: + type = ArgumentType::Immediate; + data = Utils::Bytes::Read(memory, pos + 1); + return 5; - case InstructionByte::REGISTER: - type = ArgumentType::Register; - data = static_cast(memory[pos + 1]); - return 2; + case InstructionByte::REGISTER: + type = ArgumentType::Register; + data = static_cast(memory[pos + 1]); + return 2; - case InstructionByte::MEMORY_OP: - { - type = ArgumentType::Memory; - InstructionByte const memoryArgTypeByte = static_cast(memory[pos + 1]); - switch(memoryArgTypeByte) - { - case InstructionByte::IMMEDIATE_INTEGER: - memoryValueType = ArgumentType::Immediate; - data = Utils::Bytes::Read(memory, pos + 2); - return 6; + case InstructionByte::MEMORY_OP: + { + type = ArgumentType::Memory; + InstructionByte const memoryArgTypeByte = static_cast(memory[pos + 1]); + switch(memoryArgTypeByte) + { + case InstructionByte::IMMEDIATE_INTEGER: + memoryValueType = ArgumentType::Immediate; + data = Utils::Bytes::Read(memory, pos + 2); + return 6; - case InstructionByte::REGISTER: - memoryValueType = ArgumentType::Register; - data = static_cast(memory[pos + 2]); - return 3; + case InstructionByte::REGISTER: + memoryValueType = ArgumentType::Register; + data = static_cast(memory[pos + 2]); + return 3; - default: - // TODO throw more specific error? - throw NonArgumentByte(pos); - } - } - break; + default: + // TODO throw more specific error? + throw NonArgumentByte(pos); + } + } + break; - default: - throw NonArgumentByte(pos); - } + default: + throw NonArgumentByte(pos); + } - throw std::runtime_error("Reached end of function in Parse"); - } + throw std::runtime_error("Reached end of function in Parse"); + } } \ No newline at end of file diff --git a/src/execute/error.cpp b/src/execute/error.cpp index 674e7fe..8fb17ea 100644 --- a/src/execute/error.cpp +++ b/src/execute/error.cpp @@ -2,64 +2,49 @@ namespace Execute { - std::string const & RuntimeError::GetMessage() const - { - return message; - } + std::string const & RuntimeError::GetMessage() const { return message; } - RuntimeError::RuntimeError() - : message("Undocumented runtime error") - { - } + RuntimeError::RuntimeError() : message("Undocumented runtime error") { } - RuntimeError::RuntimeError( - std::string const & what, - std::size_t const _byteLocation) - : message(what), - byteLocation(_byteLocation) - { - } + RuntimeError::RuntimeError(std::string const & what, std::size_t const _byteLocation) + : message(what), byteLocation(_byteLocation) + { } - InterruptIndexOutOfRange::InterruptIndexOutOfRange(std::size_t const location, int const index) - : RuntimeError("", location) - { - message = "Interrupt at byte "; - message += std::to_string(location); - message += " with index "; - message += std::to_string(index); - message += " is out of range"; - } + InterruptIndexOutOfRange::InterruptIndexOutOfRange(std::size_t const location, int const index) + : RuntimeError("", location) + { + message = "Interrupt at byte "; + message += std::to_string(location); + message += " with index "; + message += std::to_string(index); + message += " is out of range"; + } - AttemptedWriteToImmediate::AttemptedWriteToImmediate(std::size_t const location) - : RuntimeError("", location) - { - message = "Instruction at "; - message += std::to_string(location); - message += " attempted to write to an immediate value"; - } + AttemptedWriteToImmediate::AttemptedWriteToImmediate(std::size_t const location) : RuntimeError("", location) + { + message = "Instruction at "; + message += std::to_string(location); + message += " attempted to write to an immediate value"; + } - NonExecutableInstruction::NonExecutableInstruction(std::size_t const location) - : RuntimeError("", location) - { - message = "Attempted to execute byte at "; - message += std::to_string(location); - message += " which is not an instruction byte"; - } + NonExecutableInstruction::NonExecutableInstruction(std::size_t const location) : RuntimeError("", location) + { + message = "Attempted to execute byte at "; + message += std::to_string(location); + message += " which is not an instruction byte"; + } - NonArgumentByte::NonArgumentByte(std::size_t const location) - : RuntimeError("", location) - { - message = "Expected an argument byte (immediate, register or memory location) at "; - message += std::to_string(location); - } + NonArgumentByte::NonArgumentByte(std::size_t const location) : RuntimeError("", location) + { + message = "Expected an argument byte (immediate, register or memory location) at "; + message += std::to_string(location); + } - OutOfMemory::OutOfMemory( - std::size_t const requiredMemorySize, - std::size_t const actualMemorySize) - { - message = "Not enough memory to fit code. Actual size is "; - message += std::to_string(actualMemorySize); - message += ". Minimal required size is "; - message += std::to_string(requiredMemorySize); - } + OutOfMemory::OutOfMemory(std::size_t const requiredMemorySize, std::size_t const actualMemorySize) + { + message = "Not enough memory to fit code. Actual size is "; + message += std::to_string(actualMemorySize); + message += ". Minimal required size is "; + message += std::to_string(requiredMemorySize); + } } \ No newline at end of file diff --git a/src/execute/interrupts.cpp b/src/execute/interrupts.cpp index 0f6f2d5..c3fa740 100644 --- a/src/execute/interrupts.cpp +++ b/src/execute/interrupts.cpp @@ -5,89 +5,88 @@ namespace Execute { - void ExecuteInterrupt( - int const id, - Execute::Registers & registers, - std::vector & memory) - { - switch(id) - { - /* STDOUT interrupts */ - case 0: - std::putc(registers.A, stdout); - break; + void ExecuteInterrupt(int const id, Execute::Registers & registers, std::vector & memory) + { + switch(id) + { + /* STDOUT interrupts */ + case 0: + std::putc(registers.A, stdout); + break; - case 1: - std::printf("%i", registers.A); - break; + case 1: + std::printf("%i", registers.A); + break; - case 2: - std::printf("0x%x", registers.A); - break; + case 2: + std::printf("0x%x", registers.A); + break; - case 3: - { - unsigned const end = registers.A + registers.B; - // TODO handle out of bounds - for(unsigned i = registers.A; i < end; ++i) - { - std::putc(memory[i], stdout); - } - } - break; + case 3: + { + unsigned const end = registers.A + registers.B; + // TODO handle out of bounds + for(unsigned i = registers.A; i < end; ++i) + { + std::putc(memory[i], stdout); + } + } + break; - /* STDIN interrupts */ - case 10: - { - registers.A = std::getchar(); - if (registers.A == '\n') - { - return; - } + /* STDIN interrupts */ + case 10: + { + registers.A = std::getchar(); + if(registers.A == '\n') + { + return; + } - while(std::getchar() != '\n'); - } - break; + while(std::getchar() != '\n') + ; + } + break; - case 11: - { - if (registers.B <= 0) - { - registers.B = 0; - return; - } + case 11: + { + if(registers.B <= 0) + { + registers.B = 0; + return; + } - if (registers.A < 0 || static_cast(registers.A + registers.B) >= memory.size()) - { - throw OutOfMemory(registers.A, registers.B); - } + if(registers.A < 0 || static_cast(registers.A + registers.B) >= memory.size()) + { + throw OutOfMemory(registers.A, registers.B); + } - int charactersRead = 0; - bool newlineRead = false; - while(charactersRead < registers.B) - { - char result = std::getchar(); - if (result == '\n') - { - newlineRead = true; - break; - } + int charactersRead = 0; + bool newlineRead = false; + while(charactersRead < registers.B) + { + char result = std::getchar(); + if(result == '\n') + { + newlineRead = true; + break; + } - memory[registers.A + charactersRead] = result; - ++charactersRead; - } + memory[registers.A + charactersRead] = result; + ++charactersRead; + } - registers.B = charactersRead; + registers.B = charactersRead; - if (!newlineRead) - { - while(std::getchar() != '\n'); - } - } - break; + if(!newlineRead) + { + while(std::getchar() != '\n') + ; + } + } + break; - default: - throw InterruptIndexOutOfRange(registers.programCounter, id); - } - } + default: + throw InterruptIndexOutOfRange(registers.programCounter, id); + } + } } \ No newline at end of file diff --git a/src/execute/state.cpp b/src/execute/state.cpp index 2ee45be..6aa682a 100644 --- a/src/execute/state.cpp +++ b/src/execute/state.cpp @@ -2,27 +2,27 @@ namespace Execute { - void State::PushToStack(int const value) - { - memory[registers.stackPointer] = value & 0xFF; - memory[registers.stackPointer + 1] = (value >> 8) & 0xFF; - memory[registers.stackPointer + 2] = (value >> 16) & 0xFF; - memory[registers.stackPointer + 3] = (value >> 24) & 0xFF; + void State::PushToStack(int const value) + { + memory[registers.stackPointer] = value & 0xFF; + memory[registers.stackPointer + 1] = (value >> 8) & 0xFF; + memory[registers.stackPointer + 2] = (value >> 16) & 0xFF; + memory[registers.stackPointer + 3] = (value >> 24) & 0xFF; - registers.stackPointer += 4; + registers.stackPointer += 4; - return; - } + return; + } - int State::PopFromStack() - { - int value = static_cast(memory[registers.stackPointer - 1]) << 24; - value |= static_cast(memory[registers.stackPointer - 2]) << 16; - value |= static_cast(memory[registers.stackPointer - 3]) << 8; - value |= static_cast(memory[registers.stackPointer - 4]); + int State::PopFromStack() + { + int value = static_cast(memory[registers.stackPointer - 1]) << 24; + value |= static_cast(memory[registers.stackPointer - 2]) << 16; + value |= static_cast(memory[registers.stackPointer - 3]) << 8; + value |= static_cast(memory[registers.stackPointer - 4]); - registers.stackPointer -= 4; + registers.stackPointer -= 4; - return value; - } + return value; + } } \ No newline at end of file diff --git a/src/execute/virtualmachine.cpp b/src/execute/virtualmachine.cpp index 5a46614..864e5eb 100644 --- a/src/execute/virtualmachine.cpp +++ b/src/execute/virtualmachine.cpp @@ -7,441 +7,403 @@ namespace Execute { - std::size_t GetArguments( - InstructionByte const instruction, - std::array & arguments, - std::vector const & memory, - std::size_t const memoryPos) - { - std::size_t expectedNumberOfArguments = 0; - switch(instruction) - { - case InstructionByte::JUMP: - case InstructionByte::INTERRUPT: - case InstructionByte::CALL: - case InstructionByte::POP_INTEGER: - case InstructionByte::PUSH_INTEGER: - expectedNumberOfArguments = 1; - break; - - case InstructionByte::SET_INTEGER: - case InstructionByte::LESS_THAN_INTEGER: - case InstructionByte::GREATER_THAN_INTEGER: - case InstructionByte::EQUALS_INTEGER: - expectedNumberOfArguments = 2; - break; - - case InstructionByte::ADD_INTEGER: - case InstructionByte::SUBTRACT_INTEGER: - case InstructionByte::DIVIDE_INTEGER: - case InstructionByte::MULTIPLY_INTEGER: - case InstructionByte::SHIFT_LEFT_INTEGER: - case InstructionByte::SHIFT_RIGHT_INTEGER: - expectedNumberOfArguments = 3; - break; - - default: - throw std::runtime_error("No instruction length set for instruction byte"); - } - - std::size_t memoryOffset = memoryPos; - for(std::size_t i = 0; i < expectedNumberOfArguments; ++i) - { - memoryOffset += arguments[i].Parse(memory, memoryOffset); - } - - return memoryOffset - memoryPos; - } - - void VirtualMachine::DoArithmatic( - InstructionByte const instruction, - std::array & arguments) - { - switch (instruction) - { - case InstructionByte::ADD_INTEGER: - arguments[2].Write(arguments[0].Read(state) + arguments[1].Read(state), state); - break; - - case InstructionByte::SUBTRACT_INTEGER: - arguments[2].Write(arguments[0].Read(state) - arguments[1].Read(state), state); - break; - - case InstructionByte::DIVIDE_INTEGER: - arguments[2].Write(arguments[0].Read(state) / arguments[1].Read(state), state); - break; - - case InstructionByte::MULTIPLY_INTEGER: - arguments[2].Write(arguments[0].Read(state) * arguments[1].Read(state), state); - break; - - case InstructionByte::SHIFT_LEFT_INTEGER: - arguments[2].Write(arguments[0].Read(state) >> arguments[1].Read(state), state); - break; - - case InstructionByte::SHIFT_RIGHT_INTEGER: - arguments[2].Write(arguments[0].Read(state) << arguments[1].Read(state), state); - break; - - default: - throw std::runtime_error("Unhandled instruction bytr in DoArithmatic"); - } - } - - void VirtualMachine::SetInteger(std::array & arguments) - { - arguments[0].Write(arguments[1].Read(state), state); - } - - void VirtualMachine::ExecuteJump(std::array & arguments) - { - state.registers.programCounter = arguments[0].Read(state); - } - - void VirtualMachine::ExecuteInterrupt(std::array & arguments) - { - int const interruptNo = arguments[0].Read(state); - Execute::ExecuteInterrupt(interruptNo, state.registers, state.memory); - } - - void VirtualMachine::ExecuteCall( - std::array & arguments, - std::size_t const returnByte) - { - state.PushToStack(returnByte); - state.registers.programCounter = arguments[0].Read(state); - } - - void VirtualMachine::ExecuteReturn() - { - int const returnByte = state.PopFromStack(); - state.registers.programCounter = returnByte; - } - - void VirtualMachine::DoBooleanLogic( - InstructionByte const instruction, - std::array & arguments, - std::size_t const nextInstruction) - { - bool executeNextInstruction = false; - switch(instruction) - { - case InstructionByte::LESS_THAN_INTEGER: - executeNextInstruction = arguments[0].Read(state) < arguments[1].Read(state); - break; - - case InstructionByte::GREATER_THAN_INTEGER: - executeNextInstruction = arguments[0].Read(state) > arguments[1].Read(state); - break; - - case InstructionByte::EQUALS_INTEGER: - executeNextInstruction = arguments[0].Read(state) == arguments[1].Read(state); - break; - - default: - throw std::runtime_error("Unhandled instruction byte for boolean logic"); - } - - if (executeNextInstruction) - { - state.registers.programCounter = nextInstruction; - return; - } - - auto const argumentOffset = GetArguments( - static_cast(state.memory[nextInstruction]), - arguments, - state.memory, - nextInstruction + 1); - state.registers.programCounter = nextInstruction + 1 + argumentOffset; - } - - void VirtualMachine::ExecutePop(std::array & arguments) - { - arguments[0].Write(state.PopFromStack(), state); - } - - void VirtualMachine::ExecutePush(std::array & arguments) - { - state.PushToStack(arguments[0].Read(state)); - } - - void VirtualMachine::Step() - { - // Default to 1 byte (= 1 instruction) - std::size_t programCounterIncrement = 1; - std::array arguments; - InstructionByte const instruction = - static_cast(state.memory[state.registers.programCounter]); - switch(instruction) - { - case InstructionByte::ADD_INTEGER: - case InstructionByte::SUBTRACT_INTEGER: - case InstructionByte::DIVIDE_INTEGER: - case InstructionByte::MULTIPLY_INTEGER: - case InstructionByte::SHIFT_LEFT_INTEGER: - case InstructionByte::SHIFT_RIGHT_INTEGER: - programCounterIncrement += GetArguments( - instruction, - arguments, - state.memory, - state.registers.programCounter + 1); - DoArithmatic(instruction, arguments); - state.registers.programCounter += programCounterIncrement; - break; - - case InstructionByte::SET_INTEGER: - programCounterIncrement += GetArguments( - instruction, - arguments, - state.memory, - state.registers.programCounter + 1); - SetInteger(arguments); - state.registers.programCounter += programCounterIncrement; - break; - - case InstructionByte::JUMP: - GetArguments( - instruction, - arguments, - state.memory, - state.registers.programCounter + 1); - ExecuteJump(arguments); - break; - - case InstructionByte::INTERRUPT: - programCounterIncrement += GetArguments( - instruction, - arguments, - state.memory, - state.registers.programCounter + 1); - ExecuteInterrupt(arguments); - state.registers.programCounter += programCounterIncrement; - break; - - case InstructionByte::CALL: - programCounterIncrement += GetArguments( - instruction, - arguments, - state.memory, - state.registers.programCounter + 1); - ExecuteCall(arguments, state.registers.programCounter + programCounterIncrement); - break; - - case InstructionByte::RETURN: - ExecuteReturn(); - break; - - case InstructionByte::EXIT: - state.terminated = true; - return; - - case InstructionByte::LESS_THAN_INTEGER: - case InstructionByte::GREATER_THAN_INTEGER: - case InstructionByte::EQUALS_INTEGER: - programCounterIncrement += GetArguments( - instruction, - arguments, - state.memory, - state.registers.programCounter + 1); - DoBooleanLogic( - instruction, - arguments, - state.registers.programCounter + programCounterIncrement); - break; - - case InstructionByte::POP_INTEGER: - programCounterIncrement += GetArguments( - instruction, - arguments, - state.memory, - state.registers.programCounter + 1); - ExecutePop(arguments); - state.registers.programCounter += programCounterIncrement; - break; - - case InstructionByte::PUSH_INTEGER: - programCounterIncrement += GetArguments( - instruction, - arguments, - state.memory, - state.registers.programCounter + 1); - ExecutePush(arguments); - state.registers.programCounter += programCounterIncrement; - break; - - case InstructionByte::IMMEDIATE_INTEGER: - case InstructionByte::REGISTER: - case InstructionByte::MEMORY_OP: - case InstructionByte::LABEL: - default: - throw NonExecutableInstruction(state.registers.programCounter); - break; - } - } - - void PrintOperand(std::size_t const index, std::string const name) - { - std::printf("\n%04lu %s", index, name.c_str()); - } - - void PrintBytes(std::vector const & byteCode) - { - for(std::size_t i = 0; i < byteCode.size(); ++i) - { - InstructionByte const id = static_cast(byteCode[i]); - switch(id) - { - case InstructionByte::ADD_INTEGER: - PrintOperand(i, "addi"); - break; - - case InstructionByte::SUBTRACT_INTEGER: - PrintOperand(i, "subi"); - break; - - case InstructionByte::DIVIDE_INTEGER: - PrintOperand(i, "divi"); - break; - - case InstructionByte::MULTIPLY_INTEGER: - PrintOperand(i, "muli"); - break; - - case InstructionByte::SHIFT_LEFT_INTEGER: - PrintOperand(i, "shli"); - break; - - case InstructionByte::SHIFT_RIGHT_INTEGER: - PrintOperand(i, "shri"); - break; - - case InstructionByte::SET_INTEGER: - PrintOperand(i, "sti"); - break; - - case InstructionByte::JUMP: - PrintOperand(i, "jmp"); - break; - - case InstructionByte::INTERRUPT: - PrintOperand(i, "int"); - break; - - case InstructionByte::CALL: - PrintOperand(i, "call"); - break; - - case InstructionByte::RETURN: - PrintOperand(i, "ret"); - break; - - case InstructionByte::EXIT: - PrintOperand(i, "exit"); - break; - - case InstructionByte::LESS_THAN_INTEGER: - PrintOperand(i, "lti"); - break; - - case InstructionByte::GREATER_THAN_INTEGER: - PrintOperand(i, "gti"); - break; - - case InstructionByte::EQUALS_INTEGER: - PrintOperand(i, "eqi"); - break; - - case InstructionByte::POP_INTEGER: - PrintOperand(i, "popi"); - break; - - case InstructionByte::PUSH_INTEGER: - PrintOperand(i, "pushi"); - break; - - case InstructionByte::IMMEDIATE_INTEGER: - std::printf("$%i", Utils::Bytes::Read(byteCode, i + 1)); - i += 4u; - break; - - case InstructionByte::REGISTER: - { - std::string registerName {"A"}; - registerName[0] += byteCode[i + 1] - 1; - std::printf("%%%s", registerName.c_str()); - ++i; - } - break; - - case InstructionByte::MEMORY_OP: - std::printf("[]"); - break; - - case InstructionByte::LABEL: - std::printf("%i:", Utils::Bytes::Read(byteCode, i + 1)); - i += 4u; - break; - - default: - std::printf("UNKNOWN"); - break; - } - - std::putc(' ', stdout); - } - - std::puts(""); - } - - void VirtualMachine::Run() - { - while(!IsTerminated()) - { - Step(); - } - } - - void VirtualMachine::SingleStep() - { - if(!IsTerminated()) - { - Step(); - } - } - - void VirtualMachine::SetMemorySize(std::size_t const size) - { - state.memory.resize(size); - } - - void VirtualMachine::LoadCode( - std::vector const & byteCode, - bool const printDecodedBytes) - { - if (printDecodedBytes) - { - PrintBytes(byteCode); - } - - if (state.memory.size() < byteCode.size()) - { - throw OutOfMemory(byteCode.size(), state.memory.size()); - } - - for (std::size_t i = 0; i < byteCode.size(); ++i) - { - state.memory[i] = byteCode[i]; - } - - state.registers.stackPointer = byteCode.size(); - } - - State const & VirtualMachine::GetState() const { return state; } - Execute::InstructionByte VirtualMachine::GetCurrentInstruction() const - { - return static_cast(state.memory[state.registers.programCounter]); - } - - bool VirtualMachine::IsTerminated() const { return state.terminated; } + std::size_t GetArguments( + InstructionByte const instruction, + std::array & arguments, + std::vector const & memory, + std::size_t const memoryPos) + { + std::size_t expectedNumberOfArguments = 0; + switch(instruction) + { + case InstructionByte::JUMP: + case InstructionByte::INTERRUPT: + case InstructionByte::CALL: + case InstructionByte::POP_INTEGER: + case InstructionByte::PUSH_INTEGER: + expectedNumberOfArguments = 1; + break; + + case InstructionByte::SET_INTEGER: + case InstructionByte::LESS_THAN_INTEGER: + case InstructionByte::GREATER_THAN_INTEGER: + case InstructionByte::EQUALS_INTEGER: + expectedNumberOfArguments = 2; + break; + + case InstructionByte::ADD_INTEGER: + case InstructionByte::SUBTRACT_INTEGER: + case InstructionByte::DIVIDE_INTEGER: + case InstructionByte::MULTIPLY_INTEGER: + case InstructionByte::SHIFT_LEFT_INTEGER: + case InstructionByte::SHIFT_RIGHT_INTEGER: + expectedNumberOfArguments = 3; + break; + + default: + throw std::runtime_error("No instruction length set for instruction byte"); + } + + std::size_t memoryOffset = memoryPos; + for(std::size_t i = 0; i < expectedNumberOfArguments; ++i) + { + memoryOffset += arguments[i].Parse(memory, memoryOffset); + } + + return memoryOffset - memoryPos; + } + + void VirtualMachine::DoArithmatic(InstructionByte const instruction, std::array & arguments) + { + switch(instruction) + { + case InstructionByte::ADD_INTEGER: + arguments[2].Write(arguments[0].Read(state) + arguments[1].Read(state), state); + break; + + case InstructionByte::SUBTRACT_INTEGER: + arguments[2].Write(arguments[0].Read(state) - arguments[1].Read(state), state); + break; + + case InstructionByte::DIVIDE_INTEGER: + arguments[2].Write(arguments[0].Read(state) / arguments[1].Read(state), state); + break; + + case InstructionByte::MULTIPLY_INTEGER: + arguments[2].Write(arguments[0].Read(state) * arguments[1].Read(state), state); + break; + + case InstructionByte::SHIFT_LEFT_INTEGER: + arguments[2].Write(arguments[0].Read(state) >> arguments[1].Read(state), state); + break; + + case InstructionByte::SHIFT_RIGHT_INTEGER: + arguments[2].Write(arguments[0].Read(state) << arguments[1].Read(state), state); + break; + + default: + throw std::runtime_error("Unhandled instruction bytr in DoArithmatic"); + } + } + + void VirtualMachine::SetInteger(std::array & arguments) + { + arguments[0].Write(arguments[1].Read(state), state); + } + + void VirtualMachine::ExecuteJump(std::array & arguments) + { + state.registers.programCounter = arguments[0].Read(state); + } + + void VirtualMachine::ExecuteInterrupt(std::array & arguments) + { + int const interruptNo = arguments[0].Read(state); + Execute::ExecuteInterrupt(interruptNo, state.registers, state.memory); + } + + void VirtualMachine::ExecuteCall(std::array & arguments, std::size_t const returnByte) + { + state.PushToStack(returnByte); + state.registers.programCounter = arguments[0].Read(state); + } + + void VirtualMachine::ExecuteReturn() + { + int const returnByte = state.PopFromStack(); + state.registers.programCounter = returnByte; + } + + void VirtualMachine::DoBooleanLogic( + InstructionByte const instruction, + std::array & arguments, + std::size_t const nextInstruction) + { + bool executeNextInstruction = false; + switch(instruction) + { + case InstructionByte::LESS_THAN_INTEGER: + executeNextInstruction = arguments[0].Read(state) < arguments[1].Read(state); + break; + + case InstructionByte::GREATER_THAN_INTEGER: + executeNextInstruction = arguments[0].Read(state) > arguments[1].Read(state); + break; + + case InstructionByte::EQUALS_INTEGER: + executeNextInstruction = arguments[0].Read(state) == arguments[1].Read(state); + break; + + default: + throw std::runtime_error("Unhandled instruction byte for boolean logic"); + } + + if(executeNextInstruction) + { + state.registers.programCounter = nextInstruction; + return; + } + + auto const argumentOffset = GetArguments( + static_cast(state.memory[nextInstruction]), + arguments, + state.memory, + nextInstruction + 1); + state.registers.programCounter = nextInstruction + 1 + argumentOffset; + } + + void VirtualMachine::ExecutePop(std::array & arguments) + { + arguments[0].Write(state.PopFromStack(), state); + } + + void VirtualMachine::ExecutePush(std::array & arguments) + { + state.PushToStack(arguments[0].Read(state)); + } + + void VirtualMachine::Step() + { + // Default to 1 byte (= 1 instruction) + std::size_t programCounterIncrement = 1; + std::array arguments; + InstructionByte const instruction = static_cast(state.memory[state.registers.programCounter]); + switch(instruction) + { + case InstructionByte::ADD_INTEGER: + case InstructionByte::SUBTRACT_INTEGER: + case InstructionByte::DIVIDE_INTEGER: + case InstructionByte::MULTIPLY_INTEGER: + case InstructionByte::SHIFT_LEFT_INTEGER: + case InstructionByte::SHIFT_RIGHT_INTEGER: + programCounterIncrement + += GetArguments(instruction, arguments, state.memory, state.registers.programCounter + 1); + DoArithmatic(instruction, arguments); + state.registers.programCounter += programCounterIncrement; + break; + + case InstructionByte::SET_INTEGER: + programCounterIncrement + += GetArguments(instruction, arguments, state.memory, state.registers.programCounter + 1); + SetInteger(arguments); + state.registers.programCounter += programCounterIncrement; + break; + + case InstructionByte::JUMP: + GetArguments(instruction, arguments, state.memory, state.registers.programCounter + 1); + ExecuteJump(arguments); + break; + + case InstructionByte::INTERRUPT: + programCounterIncrement + += GetArguments(instruction, arguments, state.memory, state.registers.programCounter + 1); + ExecuteInterrupt(arguments); + state.registers.programCounter += programCounterIncrement; + break; + + case InstructionByte::CALL: + programCounterIncrement + += GetArguments(instruction, arguments, state.memory, state.registers.programCounter + 1); + ExecuteCall(arguments, state.registers.programCounter + programCounterIncrement); + break; + + case InstructionByte::RETURN: + ExecuteReturn(); + break; + + case InstructionByte::EXIT: + state.terminated = true; + return; + + case InstructionByte::LESS_THAN_INTEGER: + case InstructionByte::GREATER_THAN_INTEGER: + case InstructionByte::EQUALS_INTEGER: + programCounterIncrement + += GetArguments(instruction, arguments, state.memory, state.registers.programCounter + 1); + DoBooleanLogic(instruction, arguments, state.registers.programCounter + programCounterIncrement); + break; + + case InstructionByte::POP_INTEGER: + programCounterIncrement + += GetArguments(instruction, arguments, state.memory, state.registers.programCounter + 1); + ExecutePop(arguments); + state.registers.programCounter += programCounterIncrement; + break; + + case InstructionByte::PUSH_INTEGER: + programCounterIncrement + += GetArguments(instruction, arguments, state.memory, state.registers.programCounter + 1); + ExecutePush(arguments); + state.registers.programCounter += programCounterIncrement; + break; + + case InstructionByte::IMMEDIATE_INTEGER: + case InstructionByte::REGISTER: + case InstructionByte::MEMORY_OP: + case InstructionByte::LABEL: + default: + throw NonExecutableInstruction(state.registers.programCounter); + break; + } + } + + void PrintOperand(std::size_t const index, std::string const name) + { + std::printf("\n%04lu %s", index, name.c_str()); + } + + void PrintBytes(std::vector const & byteCode) + { + for(std::size_t i = 0; i < byteCode.size(); ++i) + { + InstructionByte const id = static_cast(byteCode[i]); + switch(id) + { + case InstructionByte::ADD_INTEGER: + PrintOperand(i, "addi"); + break; + + case InstructionByte::SUBTRACT_INTEGER: + PrintOperand(i, "subi"); + break; + + case InstructionByte::DIVIDE_INTEGER: + PrintOperand(i, "divi"); + break; + + case InstructionByte::MULTIPLY_INTEGER: + PrintOperand(i, "muli"); + break; + + case InstructionByte::SHIFT_LEFT_INTEGER: + PrintOperand(i, "shli"); + break; + + case InstructionByte::SHIFT_RIGHT_INTEGER: + PrintOperand(i, "shri"); + break; + + case InstructionByte::SET_INTEGER: + PrintOperand(i, "sti"); + break; + + case InstructionByte::JUMP: + PrintOperand(i, "jmp"); + break; + + case InstructionByte::INTERRUPT: + PrintOperand(i, "int"); + break; + + case InstructionByte::CALL: + PrintOperand(i, "call"); + break; + + case InstructionByte::RETURN: + PrintOperand(i, "ret"); + break; + + case InstructionByte::EXIT: + PrintOperand(i, "exit"); + break; + + case InstructionByte::LESS_THAN_INTEGER: + PrintOperand(i, "lti"); + break; + + case InstructionByte::GREATER_THAN_INTEGER: + PrintOperand(i, "gti"); + break; + + case InstructionByte::EQUALS_INTEGER: + PrintOperand(i, "eqi"); + break; + + case InstructionByte::POP_INTEGER: + PrintOperand(i, "popi"); + break; + + case InstructionByte::PUSH_INTEGER: + PrintOperand(i, "pushi"); + break; + + case InstructionByte::IMMEDIATE_INTEGER: + std::printf("$%i", Utils::Bytes::Read(byteCode, i + 1)); + i += 4u; + break; + + case InstructionByte::REGISTER: + { + std::string registerName {"A"}; + registerName[0] += byteCode[i + 1] - 1; + std::printf("%%%s", registerName.c_str()); + ++i; + } + break; + + case InstructionByte::MEMORY_OP: + std::printf("[]"); + break; + + case InstructionByte::LABEL: + std::printf("%i:", Utils::Bytes::Read(byteCode, i + 1)); + i += 4u; + break; + + default: + std::printf("UNKNOWN"); + break; + } + + std::putc(' ', stdout); + } + + std::puts(""); + } + + void VirtualMachine::Run() + { + while(!IsTerminated()) + { + Step(); + } + } + + void VirtualMachine::SingleStep() + { + if(!IsTerminated()) + { + Step(); + } + } + + void VirtualMachine::SetMemorySize(std::size_t const size) { state.memory.resize(size); } + + void VirtualMachine::LoadCode(std::vector const & byteCode, bool const printDecodedBytes) + { + if(printDecodedBytes) + { + PrintBytes(byteCode); + } + + if(state.memory.size() < byteCode.size()) + { + throw OutOfMemory(byteCode.size(), state.memory.size()); + } + + for(std::size_t i = 0; i < byteCode.size(); ++i) + { + state.memory[i] = byteCode[i]; + } + + state.registers.stackPointer = byteCode.size(); + } + + State const & VirtualMachine::GetState() const { return state; } + Execute::InstructionByte VirtualMachine::GetCurrentInstruction() const + { + return static_cast(state.memory[state.registers.programCounter]); + } + + bool VirtualMachine::IsTerminated() const { return state.terminated; } } \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 4cc8306..7b75832 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5,65 +5,60 @@ int main(int argc, char ** argv) { - std::string inputFile; - unsigned memorySize = 4096; - bool printSubstitutions = false, printTokens = false, printBytes = false; - bool execute = false, compile = false; - std::string outputFile("program.bin"); + std::string inputFile; + unsigned memorySize = 4096; + bool printSubstitutions = false, printTokens = false, printBytes = false; + bool execute = false, compile = false; + std::string outputFile("program.bin"); - auto cli = ( - clipp::value("input file (*.wasm or *.bin)").set(inputFile), - ( - clipp::required("-e", "--execute").set(execute), - clipp::option("-m", "--memory-size") & clipp::value("memory size in bytes (defaults to 4096)", memorySize), - clipp::option("-pb", "--print-bytes").set(printBytes) - ) | - ( - clipp::required("-c", "--compile").set(compile), - clipp::option("-o", "--output-file") & clipp::value("output file", outputFile) - ), - clipp::option("-ps", "--print-substitutions").set(printSubstitutions), - clipp::option("-pt", "--print-tokens").set(printTokens) - ); + auto cli + = (clipp::value("input file (*.wasm or *.bin)").set(inputFile), + (clipp::required("-e", "--execute").set(execute), + clipp::option("-m", "--memory-size") & clipp::value("memory size in bytes (defaults to 4096)", memorySize), + clipp::option("-pb", "--print-bytes").set(printBytes)) + | (clipp::required("-c", "--compile").set(compile), + clipp::option("-o", "--output-file") & clipp::value("output file", outputFile)), + clipp::option("-ps", "--print-substitutions").set(printSubstitutions), + clipp::option("-pt", "--print-tokens").set(printTokens)); - if (!clipp::parse(argc, argv, cli)) - { - std::cout << clipp::make_man_page(cli, argv[0]); - return 1; - } + if(!clipp::parse(argc, argv, cli)) + { + std::cout << clipp::make_man_page(cli, argv[0]); + return 1; + } - Wassembler wassembler; - wassembler.SetMemorySize(memorySize); - if (printSubstitutions) - { - wassembler.EnableSubstitutionsLogging(); - } + Wassembler wassembler; + wassembler.SetMemorySize(memorySize); + if(printSubstitutions) + { + wassembler.EnableSubstitutionsLogging(); + } - if (printTokens) - { - wassembler.EnableTokensLogging(); - } + if(printTokens) + { + wassembler.EnableTokensLogging(); + } - if (execute) - { - if (printBytes) - { - wassembler.EnableByteTranslationLogging(); - } + if(execute) + { + if(printBytes) + { + wassembler.EnableByteTranslationLogging(); + } - if (!wassembler.CompileAndRun(inputFile)) - { - exit(1); - } - } + if(!wassembler.CompileAndRun(inputFile)) + { + exit(1); + } + } - if (compile) - { - if (!wassembler.CompileToFile(inputFile, outputFile)) - { - exit(1); - } - } + if(compile) + { + if(!wassembler.CompileToFile(inputFile, outputFile)) + { + exit(1); + } + } - return 0; + return 0; } \ No newline at end of file diff --git a/src/preprocessor/preprocessor.cpp b/src/preprocessor/preprocessor.cpp index c14d9a6..6adcf57 100644 --- a/src/preprocessor/preprocessor.cpp +++ b/src/preprocessor/preprocessor.cpp @@ -2,158 +2,151 @@ #include bool trySubstitute( - std::string & line, - std::size_t const lineColumn, - std::vector const & substitutionIdentifiers, - std::vector const & substitutionValues) + std::string & line, + std::size_t const lineColumn, + std::vector const & substitutionIdentifiers, + std::vector const & substitutionValues) { - for(std::size_t i = 0; i < substitutionIdentifiers.size(); ++i) - { - if (line.compare(lineColumn, substitutionIdentifiers[i].size(), substitutionIdentifiers[i]) != 0) - { - continue; - } + for(std::size_t i = 0; i < substitutionIdentifiers.size(); ++i) + { + if(line.compare(lineColumn, substitutionIdentifiers[i].size(), substitutionIdentifiers[i]) != 0) + { + continue; + } - std::string const lineCopy = line; - line = lineCopy.substr(0, lineColumn) + substitutionValues[i]; - if (lineCopy.size() > lineColumn + substitutionIdentifiers[i].size()) - { - line += lineCopy.substr(lineColumn + substitutionIdentifiers[i].size(), lineCopy.size()); - } + std::string const lineCopy = line; + line = lineCopy.substr(0, lineColumn) + substitutionValues[i]; + if(lineCopy.size() > lineColumn + substitutionIdentifiers[i].size()) + { + line += lineCopy.substr(lineColumn + substitutionIdentifiers[i].size(), lineCopy.size()); + } - return true; - } + return true; + } - return false; + return false; } -void Preprocessor::extractComment( - std::string & line, - std::size_t const lineNumber, - std::size_t const lineColumn) +void Preprocessor::extractComment(std::string & line, std::size_t const lineNumber, std::size_t const lineColumn) { - if (line.size() <= lineColumn + 1 || - line.compare(lineColumn + 1, std::string::npos, "DEFINE") <= 0) - { - // No match or empty DEFINE statement - line = line.substr(0, lineColumn); - } + if(line.size() <= lineColumn + 1 || line.compare(lineColumn + 1, std::string::npos, "DEFINE") <= 0) + { + // No match or empty DEFINE statement + line = line.substr(0, lineColumn); + } - enum CommentParseState - { - LookForArgumentStart, - LookForArgumentEnd - }; + enum CommentParseState + { + LookForArgumentStart, + LookForArgumentEnd + }; - std::string firstArgument, secondArgument; - std::size_t argumentCount = 0, argumentStart = 0; - CommentParseState state = LookForArgumentStart; - for(std::size_t i = lineColumn + 7; i < line.size(); ++i) - { - switch(state) - { - case LookForArgumentStart: - if(!Utils::isWhitespaceCharacter(line[i])) - { - argumentStart = i; - state = CommentParseState::LookForArgumentEnd; - } - break; + std::string firstArgument, secondArgument; + std::size_t argumentCount = 0, argumentStart = 0; + CommentParseState state = LookForArgumentStart; + for(std::size_t i = lineColumn + 7; i < line.size(); ++i) + { + switch(state) + { + case LookForArgumentStart: + if(!Utils::isWhitespaceCharacter(line[i])) + { + argumentStart = i; + state = CommentParseState::LookForArgumentEnd; + } + break; - case LookForArgumentEnd: - if (Utils::isWhitespaceCharacter(line[i])) - { - switch(argumentCount) - { - case 0: - firstArgument = line.substr(argumentStart, i - argumentStart); - break; + case LookForArgumentEnd: + if(Utils::isWhitespaceCharacter(line[i])) + { + switch(argumentCount) + { + case 0: + firstArgument = line.substr(argumentStart, i - argumentStart); + break; - case 1: - secondArgument = line.substr(argumentStart, i - argumentStart); - break; + case 1: + secondArgument = line.substr(argumentStart, i - argumentStart); + break; - default: - break; - } + default: + break; + } - ++argumentCount; - state = CommentParseState::LookForArgumentStart; - } - break; - } - } + ++argumentCount; + state = CommentParseState::LookForArgumentStart; + } + break; + } + } - switch(state) - { - case CommentParseState::LookForArgumentStart: - break; + switch(state) + { + case CommentParseState::LookForArgumentStart: + break; - case CommentParseState::LookForArgumentEnd: - switch(argumentCount) - { - case 0: - firstArgument = line.substr(argumentStart); - break; + case CommentParseState::LookForArgumentEnd: + switch(argumentCount) + { + case 0: + firstArgument = line.substr(argumentStart); + break; - case 1: - secondArgument = line.substr(argumentStart); - break; + case 1: + secondArgument = line.substr(argumentStart); + break; - default: - break; - } - ++argumentCount; - break; - } + default: + break; + } + ++argumentCount; + break; + } - if (argumentCount > 0) - { - substitutionIdentifiers.push_back(firstArgument); - substitutionValues.push_back(secondArgument); - } + if(argumentCount > 0) + { + substitutionIdentifiers.push_back(firstArgument); + substitutionValues.push_back(secondArgument); + } - line = line.substr(0, lineColumn); + line = line.substr(0, lineColumn); } void Preprocessor::processLine(std::string & line, std::size_t const lineNumber) { - for(std::size_t i = 0; i < line.size(); ++i) - { - if (!Utils::isWhitespaceCharacter(line[i])) - { - if (trySubstitute(line, i, substitutionIdentifiers, substitutionValues)) - { - continue; - } + for(std::size_t i = 0; i < line.size(); ++i) + { + if(!Utils::isWhitespaceCharacter(line[i])) + { + if(trySubstitute(line, i, substitutionIdentifiers, substitutionValues)) + { + continue; + } - if (line[i] == '#') - { - extractComment(line, lineNumber, i); - return; - } - } - } + if(line[i] == '#') + { + extractComment(line, lineNumber, i); + return; + } + } + } } void Preprocessor::process(std::vector & lines) { - substitutionIdentifiers.clear(); - substitutionValues.clear(); + substitutionIdentifiers.clear(); + substitutionValues.clear(); - for(std::size_t i = 0; i < lines.size(); ++i) - { - processLine(lines[i], i); - } + for(std::size_t i = 0; i < lines.size(); ++i) + { + processLine(lines[i], i); + } } void Preprocessor::printSubstitutions() const { - for(std::size_t i = 0; i < substitutionIdentifiers.size(); ++i) - { - std::printf( - "%s -> %s\n", - substitutionIdentifiers[i].c_str(), - substitutionValues[i].c_str()); - } + for(std::size_t i = 0; i < substitutionIdentifiers.size(); ++i) + { + std::printf("%s -> %s\n", substitutionIdentifiers[i].c_str(), substitutionValues[i].c_str()); + } } \ No newline at end of file diff --git a/src/token/errors.cpp b/src/token/errors.cpp index c244110..e92830f 100644 --- a/src/token/errors.cpp +++ b/src/token/errors.cpp @@ -2,9 +2,7 @@ namespace Token { - TokenizationError::TokenizationError(Token const & token, std::string const & msg) - : errorToken(token), - errorMsg(msg) - { - } + TokenizationError::TokenizationError(Token const & token, std::string const & msg) + : errorToken(token), errorMsg(msg) + { } } \ No newline at end of file diff --git a/src/token/operandtype.cpp b/src/token/operandtype.cpp index 0b94cb0..584acfa 100644 --- a/src/token/operandtype.cpp +++ b/src/token/operandtype.cpp @@ -3,35 +3,34 @@ namespace Token { - OperandType GetOperandType(std::string const & op) - { - static std::map> const operations = - { - { "addi", OperandType::AddInteger }, - { "subi", OperandType::SubtractInteger }, - { "divi", OperandType::DivideInteger }, - { "muli", OperandType::MultiplyInteger }, - { "shri", OperandType::ShiftIntegerRight }, - { "shli", OperandType::ShiftIntegerLeft }, - { "jmp", OperandType::Jump }, - { "call", OperandType::CallFunction }, - { "ret", OperandType::ReturnFromFunction }, - { "exit", OperandType::ExitProgram }, - { "lti", OperandType::LessThanInteger }, - { "gti", OperandType::GreaterThanInteger }, - { "eqi", OperandType::EqualInteger }, - { "seti", OperandType::SetInteger }, - { "int", OperandType::Interrupt }, - { "pushi", OperandType::PushInteger}, - { "popi", OperandType::PopInteger}, - }; + OperandType GetOperandType(std::string const & op) + { + static std::map> const operations = { + {"addi", OperandType::AddInteger}, + {"subi", OperandType::SubtractInteger}, + {"divi", OperandType::DivideInteger}, + {"muli", OperandType::MultiplyInteger}, + {"shri", OperandType::ShiftIntegerRight}, + {"shli", OperandType::ShiftIntegerLeft}, + {"jmp", OperandType::Jump}, + {"call", OperandType::CallFunction}, + {"ret", OperandType::ReturnFromFunction}, + {"exit", OperandType::ExitProgram}, + {"lti", OperandType::LessThanInteger}, + {"gti", OperandType::GreaterThanInteger}, + {"eqi", OperandType::EqualInteger}, + {"seti", OperandType::SetInteger}, + {"int", OperandType::Interrupt}, + {"pushi", OperandType::PushInteger}, + {"popi", OperandType::PopInteger}, + }; - auto const & result = operations.find(op); - if (result != operations.end()) - { - return result->second; - } + auto const & result = operations.find(op); + if(result != operations.end()) + { + return result->second; + } - return OperandType::Unknown; - } + return OperandType::Unknown; + } } \ No newline at end of file diff --git a/src/token/registertype.cpp b/src/token/registertype.cpp index 656bd10..8b455ee 100644 --- a/src/token/registertype.cpp +++ b/src/token/registertype.cpp @@ -1,24 +1,19 @@ -#include #include +#include namespace Token { - RegisterType GetRegisterType(std::string const & reg) - { - static std::map> const registers = - { - { "A", RegisterType::A }, - { "B", RegisterType::B }, - { "C", RegisterType::C }, - { "D", RegisterType::D } - }; + RegisterType GetRegisterType(std::string const & reg) + { + static std::map> const registers + = {{"A", RegisterType::A}, {"B", RegisterType::B}, {"C", RegisterType::C}, {"D", RegisterType::D}}; - auto const & result = registers.find(reg); - if (result != registers.end()) - { - return result->second; - } + auto const & result = registers.find(reg); + if(result != registers.end()) + { + return result->second; + } - return RegisterType::Unknown; - } + return RegisterType::Unknown; + } } \ No newline at end of file diff --git a/src/token/token.cpp b/src/token/token.cpp index 8e8806e..4650def 100644 --- a/src/token/token.cpp +++ b/src/token/token.cpp @@ -3,251 +3,234 @@ namespace Token { - Token::Token(TokenType _type, bool validness, int const _lineNumber, int const _lineColumn) - : lineNumber(_lineNumber), - lineColumn(_lineColumn), - type(_type), - valueType(TokenValueType::None), - isValid(validness), - data(0), - errorMessage() - { - } + Token::Token(TokenType _type, bool validness, int const _lineNumber, int const _lineColumn) + : lineNumber(_lineNumber), lineColumn(_lineColumn), type(_type), valueType(TokenValueType::None), + isValid(validness), data(0), errorMessage() + { } - Token::Token(TokenType _type, std::string const & string, bool validness, int const _lineNumber, int const _lineColumn) - : lineNumber(_lineNumber), - lineColumn(_lineColumn), - type(_type), - valueType(TokenValueType::String), - isValid(validness), - data(string), - errorMessage() - { - } + Token::Token( + TokenType _type, + std::string const & string, + bool validness, + int const _lineNumber, + int const _lineColumn) + : lineNumber(_lineNumber), lineColumn(_lineColumn), type(_type), valueType(TokenValueType::String), + isValid(validness), data(string), errorMessage() + { } - Token::Token(TokenType _type, int value, bool validness, int const _lineNumber, int const _lineColumn) - : lineNumber(_lineNumber), - lineColumn(_lineColumn), - type(_type), - valueType(TokenValueType::Integer), - isValid(validness), - data(value), - errorMessage() - { - } + Token::Token(TokenType _type, int value, bool validness, int const _lineNumber, int const _lineColumn) + : lineNumber(_lineNumber), lineColumn(_lineColumn), type(_type), valueType(TokenValueType::Integer), + isValid(validness), data(value), errorMessage() + { } - Token::Token(TokenType _type, RegisterType const registerType, bool validness, int const _lineNumber, int const _lineColumn) - : lineNumber(_lineNumber), - lineColumn(_lineColumn), - type(_type), - valueType(TokenValueType::Register), - isValid(validness), - data(registerType), - errorMessage() - { - } + Token::Token( + TokenType _type, + RegisterType const registerType, + bool validness, + int const _lineNumber, + int const _lineColumn) + : lineNumber(_lineNumber), lineColumn(_lineColumn), type(_type), valueType(TokenValueType::Register), + isValid(validness), data(registerType), errorMessage() + { } - Token::Token(TokenType _type, OperandType const operandType, bool validness, int const _lineNumber, int const _lineColumn) - : lineNumber(_lineNumber), - lineColumn(_lineColumn), - type(_type), - valueType(TokenValueType::Operand), - isValid(validness), - data(operandType), - errorMessage() - { - } + Token::Token( + TokenType _type, + OperandType const operandType, + bool validness, + int const _lineNumber, + int const _lineColumn) + : lineNumber(_lineNumber), lineColumn(_lineColumn), type(_type), valueType(TokenValueType::Operand), + isValid(validness), data(operandType), errorMessage() + { } - Token::Token(Token const & other) - : lineNumber(other.lineNumber), - lineColumn(other.lineColumn), - type(other.type), - valueType(other.valueType), - isValid(other.isValid), - data(other.data), - errorMessage(other.errorMessage) - { - } + Token::Token(Token const & other) + : lineNumber(other.lineNumber), lineColumn(other.lineColumn), type(other.type), valueType(other.valueType), + isValid(other.isValid), data(other.data), errorMessage(other.errorMessage) + { } - Token Token::CreateEmptyToken(int const lineNumber, int const lineColumn) - { - return Token(TokenType::Unknown, false, lineNumber, lineColumn); - } + Token Token::CreateEmptyToken(int const lineNumber, int const lineColumn) + { + return Token(TokenType::Unknown, false, lineNumber, lineColumn); + } - Token Token::CreateErrorToken(std::string const & message, TokenType const type, int const lineNumber, int const lineColumn) - { - Token token(type, false, lineNumber, lineColumn); - token.errorMessage = message; - return token; - } + Token Token::CreateErrorToken( + std::string const & message, + TokenType const type, + int const lineNumber, + int const lineColumn) + { + Token token(type, false, lineNumber, lineColumn); + token.errorMessage = message; + return token; + } - Token Token::CreateStatementEndToken(int const lineNumber, int const lineColumn) - { - return Token(TokenType::StatementEnd, true, lineNumber, lineColumn); - } + Token Token::CreateStatementEndToken(int const lineNumber, int const lineColumn) + { + return Token(TokenType::StatementEnd, true, lineNumber, lineColumn); + } - Token Token::CreateLabelDefinitionToken(std::string const & string, int const lineNumber, int const lineColumn) - { - return Token(TokenType::LabelDefinition, string, true, lineNumber, lineColumn); - } + Token Token::CreateLabelDefinitionToken(std::string const & string, int const lineNumber, int const lineColumn) + { + return Token(TokenType::LabelDefinition, string, true, lineNumber, lineColumn); + } - Token Token::CreateLabelArgumentToken(std::string const & string, int const lineNumber, int const lineColumn) - { - return Token(TokenType::LabelArgument, string, true, lineNumber, lineColumn); - } + Token Token::CreateLabelArgumentToken(std::string const & string, int const lineNumber, int const lineColumn) + { + return Token(TokenType::LabelArgument, string, true, lineNumber, lineColumn); + } - Token Token::CreateImmediateValueToken(int const value, int const lineNumber, int const lineColumn) - { - return Token(TokenType::ImmediateInteger, value, true, lineNumber, lineColumn); - } + Token Token::CreateImmediateValueToken(int const value, int const lineNumber, int const lineColumn) + { + return Token(TokenType::ImmediateInteger, value, true, lineNumber, lineColumn); + } - Token Token::CreateRegisterToken(RegisterType const registerType, int const lineNumber, int const lineColumn) - { - return Token(TokenType::Register, registerType, registerType != RegisterType::Unknown, lineNumber, lineColumn); - } + Token Token::CreateRegisterToken(RegisterType const registerType, int const lineNumber, int const lineColumn) + { + return Token(TokenType::Register, registerType, registerType != RegisterType::Unknown, lineNumber, lineColumn); + } - Token Token::CreateOperandToken(OperandType const operandType, int const lineNumber, int const lineColumn) - { - return Token(TokenType::Operand, operandType, operandType != OperandType::Unknown, lineNumber, lineColumn); - } + Token Token::CreateOperandToken(OperandType const operandType, int const lineNumber, int const lineColumn) + { + return Token(TokenType::Operand, operandType, operandType != OperandType::Unknown, lineNumber, lineColumn); + } - Token Token::CreateMemoryToken(RegisterType const registerType, int const lineNumber, int const lineColumn) - { - if (registerType == RegisterType::Unknown) - { - return CreateErrorToken("Unknown register used", TokenType::Register, lineNumber, lineColumn); - } + Token Token::CreateMemoryToken(RegisterType const registerType, int const lineNumber, int const lineColumn) + { + if(registerType == RegisterType::Unknown) + { + return CreateErrorToken("Unknown register used", TokenType::Register, lineNumber, lineColumn); + } - return Token(TokenType::Memory, registerType, true, lineNumber, lineColumn); - } + return Token(TokenType::Memory, registerType, true, lineNumber, lineColumn); + } - Token Token::CreateMemoryToken(int const value, int const lineNumber, int const lineColumn) - { - return Token(TokenType::Memory, value, true, lineNumber, lineColumn); - } + Token Token::CreateMemoryToken(int const value, int const lineNumber, int const lineColumn) + { + return Token(TokenType::Memory, value, true, lineNumber, lineColumn); + } - std::string Token::GetName() const - { - switch(type) - { - case TokenType::ImmediateInteger: - return "immediate value"; + std::string Token::GetName() const + { + switch(type) + { + case TokenType::ImmediateInteger: + return "immediate value"; - case TokenType::Operand: - return "operand"; + case TokenType::Operand: + return "operand"; - case TokenType::Register: - return "register"; + case TokenType::Register: + return "register"; - case TokenType::StatementEnd: - return "end of statement"; + case TokenType::StatementEnd: + return "end of statement"; - case TokenType::LabelDefinition: - case TokenType::LabelArgument: - return "label"; + case TokenType::LabelDefinition: + case TokenType::LabelArgument: + return "label"; - case TokenType::Memory: - return "memory location"; + case TokenType::Memory: + return "memory location"; - case TokenType::Unknown: - default: - return "UNKNOWN"; - } - } + case TokenType::Unknown: + default: + return "UNKNOWN"; + } + } - void Token::Print() const - { - std::putc(' ', stdout); - switch(type) - { - case TokenType::ImmediateInteger: - if (isValid) - { - std::printf("%i", std::get(data)); - } - else - { - std::printf("BAD_IMM"); - } - break; + void Token::Print() const + { + std::putc(' ', stdout); + switch(type) + { + case TokenType::ImmediateInteger: + if(isValid) + { + std::printf("%i", std::get(data)); + } + else + { + std::printf("BAD_IMM"); + } + break; - case TokenType::Operand: - if (isValid) - { - OperandType const opType = std::get(data); - switch(opType) - { - case OperandType::Unknown: - std::printf("unknown_op"); - break; + case TokenType::Operand: + if(isValid) + { + OperandType const opType = std::get(data); + switch(opType) + { + case OperandType::Unknown: + std::printf("unknown_op"); + break; - default: - std::printf("op%i", static_cast(opType)); - break; - } - } - else - { - std::printf("BAD_OP"); - } - break; + default: + std::printf("op%i", static_cast(opType)); + break; + } + } + else + { + std::printf("BAD_OP"); + } + break; - case TokenType::Register: - if (isValid) - { - RegisterType const regType = std::get(data); - switch(regType) - { - default: - std::printf("%%%i", static_cast(regType)); - break; + case TokenType::Register: + if(isValid) + { + RegisterType const regType = std::get(data); + switch(regType) + { + default: + std::printf("%%%i", static_cast(regType)); + break; - case RegisterType::Unknown: - std::printf("%%unknown_reg"); - break; - } - } - else - { - std::printf("BAD_REG"); - } - break; + case RegisterType::Unknown: + std::printf("%%unknown_reg"); + break; + } + } + else + { + std::printf("BAD_REG"); + } + break; - case TokenType::StatementEnd: - std::printf("EOS"); - break; + case TokenType::StatementEnd: + std::printf("EOS"); + break; - case TokenType::LabelDefinition: - std::printf("LABEL_DEF=%s", std::get(data).c_str()); - break; + case TokenType::LabelDefinition: + std::printf("LABEL_DEF=%s", std::get(data).c_str()); + break; - case TokenType::LabelArgument: - std::printf("LABEL_ARG=%s", std::get(data).c_str()); - break; + case TokenType::LabelArgument: + std::printf("LABEL_ARG=%s", std::get(data).c_str()); + break; - case TokenType::Memory: - { - switch(valueType) - { - case TokenValueType::Integer: - std::printf("[$%i]", std::get(data)); - break; + case TokenType::Memory: + { + switch(valueType) + { + case TokenValueType::Integer: + std::printf("[$%i]", std::get(data)); + break; - case TokenValueType::Register: - std::printf("[%%%i]", static_cast(std::get(data))); - break; + case TokenValueType::Register: + std::printf("[%%%i]", static_cast(std::get(data))); + break; - default: - std::printf("[UNKNOWN_TYPE]"); - break; - } - } - break; + default: + std::printf("[UNKNOWN_TYPE]"); + break; + } + } + break; - case TokenType::Unknown: - default: - std::printf("UNKNOWN_TOKEN"); - break; - } - } + case TokenType::Unknown: + default: + std::printf("UNKNOWN_TOKEN"); + break; + } + } } \ No newline at end of file diff --git a/src/token/tokenizer.cpp b/src/token/tokenizer.cpp index d6ca65c..b1473a4 100644 --- a/src/token/tokenizer.cpp +++ b/src/token/tokenizer.cpp @@ -7,257 +7,228 @@ namespace Token { - std::optional TryParseInt(std::string const & string) - { - try - { - int value = std::stoi(string); - return std::make_optional(value); - } - catch(std::invalid_argument &) - { - return std::nullopt; - } - } + std::optional TryParseInt(std::string const & string) + { + try + { + int value = std::stoi(string); + return std::make_optional(value); + } + catch(std::invalid_argument &) + { + return std::nullopt; + } + } - Token GetCharacterLiteralToken( - std::string const & token, - std::size_t const lineNumber, - std::size_t const lineColumn) - { - for(std::size_t i = 1; i < token.size(); ++i) - { - if (token[i] == '\'') - { - if (i != 2) - { - return Token::CreateErrorToken( - "Character literal must be exactly 1 character long between single quotes", - TokenType::ImmediateInteger, - lineNumber, - lineColumn + 1u); - } - else - { - return Token::CreateImmediateValueToken( - token[1], - lineNumber, - lineColumn + 1); - } - } - } + Token + GetCharacterLiteralToken(std::string const & token, std::size_t const lineNumber, std::size_t const lineColumn) + { + for(std::size_t i = 1; i < token.size(); ++i) + { + if(token[i] == '\'') + { + if(i != 2) + { + return Token::CreateErrorToken( + "Character literal must be exactly 1 character long between single quotes", + TokenType::ImmediateInteger, + lineNumber, + lineColumn + 1u); + } + else + { + return Token::CreateImmediateValueToken(token[1], lineNumber, lineColumn + 1); + } + } + } - return Token::CreateErrorToken( - "Non terminated character literal", - TokenType::ImmediateInteger, - lineNumber, - lineColumn); - } + return Token::CreateErrorToken( + "Non terminated character literal", + TokenType::ImmediateInteger, + lineNumber, + lineColumn); + } - Token GetMemoryToken( - std::string const & token, - std::size_t const lineNumber, - std::size_t const lineColumn) - { - // Minimal example: [$1] or [%A] - if(token.size() < 4) - { - return Token::CreateErrorToken( - "Memory address statement is empty", - TokenType::Memory, - lineNumber, - lineColumn); - } + Token GetMemoryToken(std::string const & token, std::size_t const lineNumber, std::size_t const lineColumn) + { + // Minimal example: [$1] or [%A] + if(token.size() < 4) + { + return Token::CreateErrorToken( + "Memory address statement is empty", + TokenType::Memory, + lineNumber, + lineColumn); + } - if (token[0] != '[' || token[token.size() - 1] != ']') - { - return Token::CreateErrorToken( - "Non terminated memory address brackets", - TokenType::Memory, - lineNumber, - lineColumn); - } + if(token[0] != '[' || token[token.size() - 1] != ']') + { + return Token::CreateErrorToken( + "Non terminated memory address brackets", + TokenType::Memory, + lineNumber, + lineColumn); + } - char const memoryPrefix = token[1]; - std::string const valueString = token.substr(2, token.size() - 3u); - if (memoryPrefix == '$') - { - auto const result = TryParseInt(valueString); + char const memoryPrefix = token[1]; + std::string const valueString = token.substr(2, token.size() - 3u); + if(memoryPrefix == '$') + { + auto const result = TryParseInt(valueString); - if (result.has_value()) - { - return Token::CreateMemoryToken( - result.value(), - lineNumber, - lineColumn); - } + if(result.has_value()) + { + return Token::CreateMemoryToken(result.value(), lineNumber, lineColumn); + } - return Token::CreateErrorToken( - "Memory immediate address cannot be parsed as an integer", - TokenType::Memory, - lineNumber, - lineColumn); - } - else if (memoryPrefix == '%') - { - return Token::CreateMemoryToken( - GetRegisterType(valueString), - lineNumber, - lineColumn); - } + return Token::CreateErrorToken( + "Memory immediate address cannot be parsed as an integer", + TokenType::Memory, + lineNumber, + lineColumn); + } + else if(memoryPrefix == '%') + { + return Token::CreateMemoryToken(GetRegisterType(valueString), lineNumber, lineColumn); + } - return Token::CreateErrorToken( - "Memory immediate address contains an unexpected value", - TokenType::Memory, - lineNumber, - lineColumn + 1u); - } + return Token::CreateErrorToken( + "Memory immediate address contains an unexpected value", + TokenType::Memory, + lineNumber, + lineColumn + 1u); + } - Token GetUnterminatedCharacterLiteralError( - std::size_t const lineNumber, - std::size_t const lineColumn) - { - return Token::CreateErrorToken( - "Unterminated character or string literal", - TokenType::Unknown, - lineNumber, - lineColumn); - } + Token GetUnterminatedCharacterLiteralError(std::size_t const lineNumber, std::size_t const lineColumn) + { + return Token::CreateErrorToken( + "Unterminated character or string literal", + TokenType::Unknown, + lineNumber, + lineColumn); + } - Token Tokenizer::ExtractToken( - std::string const & string, - std::size_t const lineNumber, - std::size_t const lineColumn) const - { - char const prefix = string[0]; - switch(prefix) - { - case '$': - { - auto const result = TryParseInt(string.substr(1, string.size())); + Token Tokenizer::ExtractToken( + std::string const & string, + std::size_t const lineNumber, + std::size_t const lineColumn) const + { + char const prefix = string[0]; + switch(prefix) + { + case '$': + { + auto const result = TryParseInt(string.substr(1, string.size())); - if (result.has_value()) - { - return Token::CreateImmediateValueToken( - result.value(), - lineNumber, - lineColumn); - } + if(result.has_value()) + { + return Token::CreateImmediateValueToken(result.value(), lineNumber, lineColumn); + } - return Token::CreateErrorToken( - "Immediate cannot be parsed as an integer", - TokenType::ImmediateInteger, - lineNumber, - lineColumn); - } + return Token::CreateErrorToken( + "Immediate cannot be parsed as an integer", + TokenType::ImmediateInteger, + lineNumber, + lineColumn); + } - case '%': - return Token::CreateRegisterToken(GetRegisterType( - string.substr(1, string.size())), - lineNumber, - lineColumn); + case '%': + return Token::CreateRegisterToken( + GetRegisterType(string.substr(1, string.size())), + lineNumber, + lineColumn); - case '\'': - return GetCharacterLiteralToken(string, lineNumber, lineColumn); + case '\'': + return GetCharacterLiteralToken(string, lineNumber, lineColumn); - case ';': - return Token::CreateStatementEndToken(lineNumber, lineColumn); + case ';': + return Token::CreateStatementEndToken(lineNumber, lineColumn); - case '[': - return GetMemoryToken(string, lineNumber, lineColumn); + case '[': + return GetMemoryToken(string, lineNumber, lineColumn); - default: - break; - } + default: + break; + } - char const postfix = string[string.size() - 1]; - switch(postfix) - { - case ']': - return GetMemoryToken(string, lineNumber, lineColumn); + char const postfix = string[string.size() - 1]; + switch(postfix) + { + case ']': + return GetMemoryToken(string, lineNumber, lineColumn); - case ':': - // TODO check if label is an Operand? - return Token::CreateLabelDefinitionToken( - string.substr(0, string.size() - 1), - lineNumber, - lineColumn); + case ':': + // TODO check if label is an Operand? + return Token::CreateLabelDefinitionToken(string.substr(0, string.size() - 1), lineNumber, lineColumn); - case '\'': - case '\"': - // This shouldn't happen - return GetUnterminatedCharacterLiteralError(lineNumber, lineColumn); - } + case '\'': + case '\"': + // This shouldn't happen + return GetUnterminatedCharacterLiteralError(lineNumber, lineColumn); + } - OperandType const opType = GetOperandType(string); - if (opType != OperandType::Unknown) - { - return Token::CreateOperandToken(opType, lineNumber, lineColumn); - } + OperandType const opType = GetOperandType(string); + if(opType != OperandType::Unknown) + { + return Token::CreateOperandToken(opType, lineNumber, lineColumn); + } - // Last resort: it must be a jump target - return Token::CreateLabelArgumentToken(string, lineNumber, lineColumn); - } + // Last resort: it must be a jump target + return Token::CreateLabelArgumentToken(string, lineNumber, lineColumn); + } - void Tokenizer::Tokenize( - std::string const & line, - std::size_t const lineNumber, - std::vector & tokens) - { - for(std::size_t column = 0u; column < line.size(); ++column) - { - if (Utils::isWhitespaceCharacter(line[column])) - { - continue; - } + void Tokenizer::Tokenize(std::string const & line, std::size_t const lineNumber, std::vector & tokens) + { + for(std::size_t column = 0u; column < line.size(); ++column) + { + if(Utils::isWhitespaceCharacter(line[column])) + { + continue; + } - switch(line[column]) - { - case '\'': - case '\"': - { - auto const result = Utils::getValueSurroundedBy( - line, - column, - line[column]); - if (result.has_value()) - { - tokens.push_back(ExtractToken(result.value(), lineNumber, column)); - column += result.value().size() - 1; - } - else - { - tokens.push_back( - GetUnterminatedCharacterLiteralError(lineNumber, column)); + switch(line[column]) + { + case '\'': + case '\"': + { + auto const result = Utils::getValueSurroundedBy(line, column, line[column]); + if(result.has_value()) + { + tokens.push_back(ExtractToken(result.value(), lineNumber, column)); + column += result.value().size() - 1; + } + else + { + tokens.push_back(GetUnterminatedCharacterLiteralError(lineNumber, column)); - // Parsing must stop here, the line is malformed - return; - } - } - break; + // Parsing must stop here, the line is malformed + return; + } + } + break; - case ';': - tokens.push_back(ExtractToken(";", lineNumber, column)); - break; + case ';': + tokens.push_back(ExtractToken(";", lineNumber, column)); + break; - default: - { - auto const result = Utils::getValueSurroundedByWhitespace(line, column); - auto const lastCharacterIndex = result.size() - 1; - if (result[lastCharacterIndex] == ';') - { - tokens.push_back(ExtractToken(result.substr(0, result.size() -1), lineNumber, column)); - tokens.push_back(ExtractToken(";", lineNumber, column + lastCharacterIndex)); - } - else - { - tokens.push_back(ExtractToken(result, lineNumber, column)); - } + default: + { + auto const result = Utils::getValueSurroundedByWhitespace(line, column); + auto const lastCharacterIndex = result.size() - 1; + if(result[lastCharacterIndex] == ';') + { + tokens.push_back(ExtractToken(result.substr(0, result.size() - 1), lineNumber, column)); + tokens.push_back(ExtractToken(";", lineNumber, column + lastCharacterIndex)); + } + else + { + tokens.push_back(ExtractToken(result, lineNumber, column)); + } - column += result.size(); - } - break; - } - } - } + column += result.size(); + } + break; + } + } + } } \ No newline at end of file diff --git a/src/utils.cpp b/src/utils.cpp index d786925..39abc60 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -2,63 +2,53 @@ namespace Utils { - bool isWhitespaceCharacter(char const c) - { - return c == '\n' || c == ' ' || c == '\t' || c == '\r'; - } + bool isWhitespaceCharacter(char const c) { return c == '\n' || c == ' ' || c == '\t' || c == '\r'; } - std::optional getValueSurroundedBy( - std::string const & src, - std::size_t const pos, - char const surroundingCharacter) - { - for(std::size_t i = pos + 1; i < src.size(); ++i) - { - if (src[i] == surroundingCharacter) - { - return std::make_optional(src.substr(pos, (i + 1) - pos)); - } - } + std::optional + getValueSurroundedBy(std::string const & src, std::size_t const pos, char const surroundingCharacter) + { + for(std::size_t i = pos + 1; i < src.size(); ++i) + { + if(src[i] == surroundingCharacter) + { + return std::make_optional(src.substr(pos, (i + 1) - pos)); + } + } - return std::nullopt; - } + return std::nullopt; + } - std::string getValueSurroundedByWhitespace( - std::string const & src, - std::size_t const pos) - { - for(std::size_t i = pos + 1; i < src.size(); ++i) - { - if (isWhitespaceCharacter(src[i])) - { - return src.substr(pos, i - pos); - } - } + std::string getValueSurroundedByWhitespace(std::string const & src, std::size_t const pos) + { + for(std::size_t i = pos + 1; i < src.size(); ++i) + { + if(isWhitespaceCharacter(src[i])) + { + return src.substr(pos, i - pos); + } + } - return src.substr(pos); - } + return src.substr(pos); + } - namespace Bytes - { - void Write( - int const value, - std::vector & vec, - std::size_t const pos) - { - vec[pos] = value & 0xFF; - vec[pos + 1] = (value >> 8) & 0xFF; - vec[pos + 2] = (value >> 16) & 0xFF; - vec[pos + 3] = (value >> 24) & 0xFF; - } + namespace Bytes + { + void Write(int const value, std::vector & vec, std::size_t const pos) + { + vec[pos] = value & 0xFF; + vec[pos + 1] = (value >> 8) & 0xFF; + vec[pos + 2] = (value >> 16) & 0xFF; + vec[pos + 3] = (value >> 24) & 0xFF; + } - int Read(std::vector const & vec, std::size_t const pos) - { - int value = vec[pos]; - value |= static_cast(vec[pos + 1]) << 8; - value |= static_cast(vec[pos + 2]) << 16; - value |= static_cast(vec[pos + 3]) << 24; + int Read(std::vector const & vec, std::size_t const pos) + { + int value = vec[pos]; + value |= static_cast(vec[pos + 1]) << 8; + value |= static_cast(vec[pos + 2]) << 16; + value |= static_cast(vec[pos + 3]) << 24; - return value; - } - } + return value; + } + } } \ No newline at end of file diff --git a/src/wassembler.cpp b/src/wassembler.cpp index 95dce95..3f2a19b 100644 --- a/src/wassembler.cpp +++ b/src/wassembler.cpp @@ -8,255 +8,234 @@ void PrintBadToken(Token::Token const & token, std::vector const & lines) { - std::printf("at line number %i, column %i: ", - token.lineNumber + 1, - token.lineColumn + 1); - std::puts(token.errorMessage.c_str()); + std::printf("at line number %i, column %i: ", token.lineNumber + 1, token.lineColumn + 1); + std::puts(token.errorMessage.c_str()); - std::printf("%s\n", lines[token.lineNumber].c_str()); - for(int i = 0; i < token.lineColumn; ++i) - { - std::putc(' ', stdout); - } - std::puts("^"); + std::printf("%s\n", lines[token.lineNumber].c_str()); + for(int i = 0; i < token.lineColumn; ++i) + { + std::putc(' ', stdout); + } + std::puts("^"); } void PrintTokenError(Token::TokenizationError const & err, std::vector const & lines) { - std::printf("%s ", err.errorMsg.c_str()); - PrintBadToken(err.errorToken, lines); + std::printf("%s ", err.errorMsg.c_str()); + PrintBadToken(err.errorToken, lines); } bool Wassembler::LoadTextFile(std::string const & filePath, std::vector & lines) const { - std::ifstream input(filePath); - if (!input.is_open()) - { - return false; - } + std::ifstream input(filePath); + if(!input.is_open()) + { + return false; + } - std::string line; - while(std::getline(input, line)) - { - lines.push_back(line); - } - input.close(); + std::string line; + while(std::getline(input, line)) + { + lines.push_back(line); + } + input.close(); - return true; + return true; } bool Wassembler::Preprocess(std::vector & lines) const { - Preprocessor preprocessor; - preprocessor.process(lines); - if (printSubstitutions) - { - preprocessor.printSubstitutions(); - } + Preprocessor preprocessor; + preprocessor.process(lines); + if(printSubstitutions) + { + preprocessor.printSubstitutions(); + } - return true; + return true; } bool Wassembler::Tokenize(std::vector const & lines, std::vector & tokens) const { - Token::Tokenizer tokenizer; - bool tokenizationError = false; - for(std::size_t i = 0; i < lines.size(); ++i) - { - try - { - tokenizer.Tokenize(lines[i], i, tokens); - } - catch(Token::TokenizationError & err) - { - tokenizationError = true; - PrintTokenError(err, lines); - } - } + Token::Tokenizer tokenizer; + bool tokenizationError = false; + for(std::size_t i = 0; i < lines.size(); ++i) + { + try + { + tokenizer.Tokenize(lines[i], i, tokens); + } + catch(Token::TokenizationError & err) + { + tokenizationError = true; + PrintTokenError(err, lines); + } + } - if (printTokens && tokens.size() > 0) - { - int previousLine = tokens[0].lineNumber; - std::printf("Line %04i: ", previousLine); - for(auto const & token : tokens) - { - if (token.lineNumber != previousLine) - { - std::putc('\n', stdout); - previousLine = token.lineNumber; - std::printf("Line %04i: ", previousLine); - } + if(printTokens && tokens.size() > 0) + { + int previousLine = tokens[0].lineNumber; + std::printf("Line %04i: ", previousLine); + for(auto const & token: tokens) + { + if(token.lineNumber != previousLine) + { + std::putc('\n', stdout); + previousLine = token.lineNumber; + std::printf("Line %04i: ", previousLine); + } - token.Print(); - } - std::putc('\n', stdout); - } + token.Print(); + } + std::putc('\n', stdout); + } - // Validate the syntax - bool syntaxError = false; - for(auto const & token : tokens) - { - if (!token.isValid) - { - std::printf("Syntax error "); - PrintBadToken(token, lines); - syntaxError = true; - } - } + // Validate the syntax + bool syntaxError = false; + for(auto const & token: tokens) + { + if(!token.isValid) + { + std::printf("Syntax error "); + PrintBadToken(token, lines); + syntaxError = true; + } + } - return !(syntaxError || tokenizationError); + return !(syntaxError || tokenizationError); } bool Wassembler::CompileToBytes( - std::vector const & tokens, - std::vector const & lines, - std::vector & bytes) const + std::vector const & tokens, + std::vector const & lines, + std::vector & bytes) const { - Compile::Compiler compiler; - try - { - compiler.Compile(tokens, bytes); - } - catch(Compile::CompilationError & e) - { - std::printf("Semantic error "); - PrintBadToken(e.errorToken, lines); + Compile::Compiler compiler; + try + { + compiler.Compile(tokens, bytes); + } + catch(Compile::CompilationError & e) + { + std::printf("Semantic error "); + PrintBadToken(e.errorToken, lines); - return false; - } + return false; + } - return true; + return true; } void Wassembler::ExecuteCode(std::vector const & bytes) { - vm.LoadCode(bytes, printTranslatedBytes); - // TODO clear memory? - vm.Run(); + vm.LoadCode(bytes, printTranslatedBytes); + // TODO clear memory? + vm.Run(); } -bool Wassembler::CompileFile( - std::string const & filePath, - std::vector & bytes) const +bool Wassembler::CompileFile(std::string const & filePath, std::vector & bytes) const { - std::vector lines; - if (!LoadTextFile(filePath, lines)) - { - std::printf("Error: Cannot open file %s for reading", filePath.c_str()); - return false; - } + std::vector lines; + if(!LoadTextFile(filePath, lines)) + { + std::printf("Error: Cannot open file %s for reading", filePath.c_str()); + return false; + } - if(!Preprocess(lines)) - { - std::puts("Aborting due to preprocessor error(s)"); - return false; - } + if(!Preprocess(lines)) + { + std::puts("Aborting due to preprocessor error(s)"); + return false; + } - std::vector tokens; - if (!Tokenize(lines, tokens) || !CompileToBytes(tokens, lines, bytes)) - { - std::puts("Aborting due to syntax error(s)"); - return false; - } + std::vector tokens; + if(!Tokenize(lines, tokens) || !CompileToBytes(tokens, lines, bytes)) + { + std::puts("Aborting due to syntax error(s)"); + return false; + } - return true; + return true; } -void Wassembler::SetMemorySize(unsigned const size) -{ - vm.SetMemorySize(size); -} +void Wassembler::SetMemorySize(unsigned const size) { vm.SetMemorySize(size); } -void Wassembler::EnableSubstitutionsLogging() -{ - printSubstitutions = true; -} +void Wassembler::EnableSubstitutionsLogging() { printSubstitutions = true; } -void Wassembler::EnableTokensLogging() -{ - printTokens = true; -} +void Wassembler::EnableTokensLogging() { printTokens = true; } -void Wassembler::EnableByteTranslationLogging() -{ - printTranslatedBytes = true; -} +void Wassembler::EnableByteTranslationLogging() { printTranslatedBytes = true; } bool Wassembler::CompileAndRun(std::string const & filePath) { - std::vector bytes; - if (filePath.size() > 4 && filePath.compare(filePath.size() - 4, 4, ".bin") == 0) - { - std::ifstream inputFile(filePath); - if (!inputFile.is_open()) - { - std::printf("Error: Cannot open file %s for reading", filePath.c_str()); - return false; - } + std::vector bytes; + if(filePath.size() > 4 && filePath.compare(filePath.size() - 4, 4, ".bin") == 0) + { + std::ifstream inputFile(filePath); + if(!inputFile.is_open()) + { + std::printf("Error: Cannot open file %s for reading", filePath.c_str()); + return false; + } - std::size_t previousSize = 0; - bytes.resize(100); - while(inputFile.read(reinterpret_cast(&bytes[previousSize]), 100)) - { - previousSize = bytes.size(); - bytes.resize(bytes.size() + 100); - } + std::size_t previousSize = 0; + bytes.resize(100); + while(inputFile.read(reinterpret_cast(&bytes[previousSize]), 100)) + { + previousSize = bytes.size(); + bytes.resize(bytes.size() + 100); + } - bytes.resize(bytes.size() - (100 - inputFile.gcount())); - } - else if (filePath.size() > 5 && - filePath.compare(filePath.size() - 5, 5, ".wasm") == 0) - { - if (!CompileFile(filePath, bytes)) - { - return false; - } - } - else - { - std::printf( - "Error: unrecognized file extension on input file %s", - filePath.c_str()); + bytes.resize(bytes.size() - (100 - inputFile.gcount())); + } + else if(filePath.size() > 5 && filePath.compare(filePath.size() - 5, 5, ".wasm") == 0) + { + if(!CompileFile(filePath, bytes)) + { + return false; + } + } + else + { + std::printf("Error: unrecognized file extension on input file %s", filePath.c_str()); - return false; - } + return false; + } - try - { - ExecuteCode(bytes); - } - catch (Execute::RuntimeError const & e) - { - std::puts(e.GetMessage().c_str()); - std::puts("Aborting due to runtime error(s)"); - return false; - } + try + { + ExecuteCode(bytes); + } + catch(Execute::RuntimeError const & e) + { + std::puts(e.GetMessage().c_str()); + std::puts("Aborting due to runtime error(s)"); + return false; + } - return true; + return true; } -bool Wassembler::CompileToFile( - std::string const & inputFilePath, - std::string const & outputFilePath) +bool Wassembler::CompileToFile(std::string const & inputFilePath, std::string const & outputFilePath) { - std::vector bytes; - if (!CompileFile(inputFilePath, bytes)) - { - return false; - } + std::vector bytes; + if(!CompileFile(inputFilePath, bytes)) + { + return false; + } - std::ofstream output(outputFilePath, std::ios::binary | std::ios::trunc); - if (!output.is_open()) - { - std::printf("Error: Cannot open file %s for writing", outputFilePath.c_str()); - return false; - } + std::ofstream output(outputFilePath, std::ios::binary | std::ios::trunc); + if(!output.is_open()) + { + std::printf("Error: Cannot open file %s for writing", outputFilePath.c_str()); + return false; + } - if (!output.write(reinterpret_cast(bytes.data()), bytes.size())) - { - std::printf("Error: An error occurred whilst writing to %s", outputFilePath.c_str()); - return false; - } + if(!output.write(reinterpret_cast(bytes.data()), bytes.size())) + { + std::printf("Error: An error occurred whilst writing to %s", outputFilePath.c_str()); + return false; + } - return true; + return true; } \ No newline at end of file