├── Console.hpp ├── Database.hpp ├── Demangler.hpp ├── Eye.hpp ├── Iris.cpp ├── Iris.hpp ├── LICENSE ├── Linker.hpp ├── Nerve.hpp ├── PE.hpp ├── Pupil.hpp ├── README.md ├── Structures.hpp ├── Utilities.hpp ├── VisualDebugger.hpp └── X64.hpp /Console.hpp: -------------------------------------------------------------------------------- 1 | //Copyright 2020 Iris Technologies, All Rights Reserved 2 | #pragma once 3 | #include 4 | #include 5 | #include 6 | 7 | namespace ProjectIris 8 | { 9 | namespace Console 10 | { 11 | __forceinline void Append(const string& Message) noexcept 12 | { 13 | Database::ConsoleBuffer.append(Message); 14 | } 15 | 16 | __forceinline void LinkerError(const string& Message) noexcept 17 | { 18 | Database::LinkerError = true; 19 | Database::ConsoleBuffer.append(Message); 20 | } 21 | 22 | __forceinline void PupilError(const string& File, const size_t Line, const size_t Character, const string& Message) 23 | { 24 | Database::ConsoleBuffer.append("\n\nError at '" + File + "', " + to_string(Line) + " : " + to_string(Character) + " -> " + Message); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /Database.hpp: -------------------------------------------------------------------------------- 1 | //Copyright 2020 Iris Technologies, All Rights Reserved 2 | #pragma once 3 | #include 4 | 5 | namespace ProjectIris 6 | { 7 | namespace Database 8 | { 9 | bool LastMessage = false, InitApp = false, IsConsole = false, LinkerError = false, PupilError = false, UseVisualDebugger = false, ReportPupil = false; 10 | 11 | OperatingSystem os = OperatingSystem::Windows; 12 | 13 | MeasureTypes mtp = MeasureTypes::Microseconds; 14 | 15 | ProjectType pt = ProjectType::Sandbox; 16 | 17 | unsigned short MajorWindowsVersion = 5, MinorWindowsVersion = 2, MajorAppVersion = 0, MinorAppVersion = 1; 18 | 19 | size_t ProjectSourceLength, ActualLine = 1, ActualCharacter = 1; 20 | 21 | string ProjectPath, OutputFolder, SourceFolder, ConsoleBuffer, ProjectName, ActualFile, Commands; 22 | 23 | ErrorPoint Report; 24 | 25 | vector Rdata, Text, Binary = {0x4d, 0x5a, 0x90, 0, 3, 0, 0, 0, 4, 0, 0, 0, 0xff, 0xff, 0, 0, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xf8, 0, 0, 0, 0x0e, 0, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 1, 0x4c, 0xcd, 0x21, 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x20, 0x77, 0x61, 0x73, 0x20, 0x64, 0x6f, 0x6e, 0x65, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x49, 0x72, 0x69, 0x73, 0x20, 0x4c, 0x69, 0x6e, 0x6b, 0x65, 0x72, 0x2e, 0x0d, 0x0d, 0x0a, 0x24, 0x60, 0xed, 0xd0, 0x9c, 0x24, 0x8c, 0xbe, 0xcf, 0x24, 0x8c, 0xbe, 0xcf, 0x24, 0x8c, 0xbe, 0xcf, 0x7f, 0xe4, 0xbd, 0xce, 0x2e, 0x8c, 0xbe, 0xcf, 0x7f, 0xe4, 0xbb, 0xce, 0xa3, 0x8c, 0xbe, 0xcf, 0x37, 0xea, 0xbd, 0xce, 0x35, 0x8c, 0xbe, 0xcf, 0x37, 0xea, 0xbb, 0xce, 4, 0x8c, 0xbe, 0xcf, 0x37, 0xea, 0xba, 0xce, 0x2a, 0x8c, 0xbe, 0xcf, 0x7f, 0xe4, 0xba, 0xce, 0x37, 0x8c, 0xbe, 0xcf, 0x18, 0xeb, 0xba, 0xce, 0x25, 0x8c, 0xbe, 0xcf, 0x7f, 0xe4, 0xbf, 0xce, 0x2d, 0x8c, 0xbe, 0xcf, 0x24, 0x8c, 0xbf, 0xcf, 0x71, 0x8c, 0xbe, 0xcf, 0x18, 0xeb, 0xbb, 0xce, 0x23, 0x8c, 0xbe, 0xcf, 0x18, 0xeb, 0xbe, 0xce, 0x25, 0x8c, 0xbe, 0xcf, 0x18, 0xeb, 0x41, 0xcf, 0x25, 0x8c, 0xbe, 0xcf, 0x18, 0xeb, 0xbc, 0xce, 0x25, 0x8c, 0xbe, 0xcf, 0x52, 0x69, 0x63, 0x68, 0x24, 0x8c, 0xbe, 0xcf, 0x50, 0x45, 0, 0, 0x64, 0x86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xf0, 0, 0x23, 0, 0xb, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0, 0, 0x40, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0x60, 0x81, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2e, 0x74, 0x65, 0x78, 0x74, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x20, 0, 0, 0x70}; 26 | 27 | vector IrisFiles, IgnoredIris, IgnoredRetina, PupilFiles; 28 | 29 | vector NativeLibraries; 30 | 31 | vector ExportedSymbols; 32 | 33 | vector NativeSections; 34 | 35 | vector PupilFInstructions; 36 | } 37 | } -------------------------------------------------------------------------------- /Demangler.hpp: -------------------------------------------------------------------------------- 1 | //Copyright 2020 Iris Technologies, All Rights Reserved 2 | #pragma once 3 | #include 4 | 5 | using namespace std; 6 | 7 | namespace ProjectIris 8 | { 9 | namespace Demangler 10 | { 11 | //I know it's pretty simple, but i have other priorities, TODO 12 | __forceinline string Demangle(const string& Name) noexcept 13 | { 14 | string name(Name); 15 | if(name[0] == '_') 16 | name.erase(0, 1); 17 | for (size_t i = name.size() - 1; i >= 0; --i) 18 | if (name[i] < '0' || name[i] > '9') 19 | { 20 | if (name[i] == '@') 21 | name.erase(i, name.size() - i); 22 | break; 23 | } 24 | return name; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Eye.hpp: -------------------------------------------------------------------------------- 1 | //Copyright 2020 Iris Technologies, All Rights Reserved 2 | #pragma once 3 | #include 4 | #include 5 | #include 6 | 7 | namespace ProjectIris 8 | { 9 | namespace Eye 10 | { 11 | __forceinline void Process() noexcept 12 | { 13 | PE::WriteTextSection(); 14 | ErrorPoint ep; 15 | NativeLibrary lf; 16 | string Keyword; 17 | size_t Line = 1, Character = 0, LastLine, LastCharacter; 18 | bool IsIgnore = false, IsError = false, InvalidCharName = false, IsType = false, IsName = false, IsMeasureType = false, IsNatlib = false, FirstChar = false; 19 | chrono::steady_clock::time_point a = Utilities::TimePoint(); 20 | const string EyeContent = Utilities::ReadFile(Database::ProjectPath); 21 | for(size_t x = 0; x < EyeContent.size(); ++x) 22 | { 23 | if(EyeContent[x] == '\n') 24 | { 25 | ++Line; 26 | Character = 0; 27 | } 28 | else 29 | ++Character; 30 | if(IsNatlib) 31 | { 32 | if(EyeContent[x] == '\n' || EyeContent[x] == ' ') 33 | { 34 | if (Keyword.size() > 0) 35 | { 36 | IsNatlib = false; 37 | FirstChar = false; 38 | if(Utilities::FileExists(Keyword)) 39 | { 40 | bool Exists = false; 41 | size_t ExistingLine, ExistingCharacter; 42 | for(size_t xx = 0; xx < Database::NativeLibraries.size(); ++xx) 43 | if(Keyword == Database::NativeLibraries[xx].Name) 44 | { 45 | ExistingLine = Database::NativeLibraries[xx].Line; 46 | ExistingCharacter = Database::NativeLibraries[xx].Character; 47 | Exists = true; 48 | break; 49 | } 50 | if(!Exists) 51 | { 52 | lf.Line = LastLine; 53 | lf.Character = LastCharacter; 54 | lf.Name = Keyword; 55 | Database::NativeLibraries.push_back(lf); 56 | } 57 | else 58 | { 59 | IsError = true; 60 | ep.Line = Line; 61 | ep.Character = Character; 62 | ep.Message = "The native library declaration '" + Keyword + "' starting at " + to_string(LastLine) + " : " + to_string(LastCharacter) + " is already specified at " + to_string(ExistingLine) + " : " + to_string(ExistingCharacter); 63 | break; 64 | } 65 | } 66 | else 67 | { 68 | IsNatlib = false; 69 | IsError = true; 70 | ep.Line = Line; 71 | ep.Character = Character; 72 | ep.Message = "The native library declaration '" + Keyword + "' starting at " + to_string(LastLine) + " : " + to_string(LastCharacter) + ", does not exists"; 73 | Keyword.clear(); 74 | break; 75 | } 76 | Keyword.clear(); 77 | } 78 | } 79 | else if(!FirstChar) 80 | { 81 | FirstChar = true; 82 | LastCharacter = Character; 83 | LastLine = Line; 84 | Keyword.push_back(EyeContent[x]); 85 | } 86 | else 87 | Keyword.push_back(EyeContent[x]); 88 | } 89 | else if(IsIgnore) 90 | { 91 | if(EyeContent[x] == '\n' || EyeContent[x] == ' ') 92 | { 93 | IsIgnore = false; 94 | FirstChar = false; 95 | if(Keyword.size() > 0) 96 | { 97 | if(!Utilities::FileExists(Keyword)) 98 | { 99 | IsError = true; 100 | ep.Line = Line; 101 | ep.Character = Character; 102 | ep.Message = "The ignored iris file declaration '" + Keyword + "' starting at " + to_string(LastLine) + " : " + to_string(LastCharacter) + " does not exists"; 103 | break; 104 | } 105 | else 106 | Database::IgnoredIris.push_back(Keyword); 107 | Keyword.clear(); 108 | } 109 | } 110 | else if(!FirstChar) 111 | { 112 | FirstChar = true; 113 | LastLine = Line; 114 | LastCharacter = Character; 115 | Keyword.push_back(EyeContent[x]); 116 | } 117 | else 118 | Keyword.push_back(EyeContent[x]); 119 | } 120 | else if(IsType) 121 | { 122 | if(EyeContent[x] == '\n' || EyeContent[x] == ' ') 123 | { 124 | IsType = false; 125 | FirstChar = false; 126 | const size_t h = Utilities::Hash(Keyword); 127 | if(h == Hashes::Executable) 128 | Database::pt = ProjectType::Executable; 129 | else if(h == Hashes::Library) 130 | Database::pt = ProjectType::Library; 131 | else if(h != Hashes::Sandbox) 132 | { 133 | IsError = true; 134 | ep.Line = Line; 135 | ep.Character = Character; 136 | ep.Message = "The project type specifier '" + Keyword + "' starting at " + to_string(LastLine) + " : " + to_string(LastCharacter) + ", is unrecognized"; 137 | Keyword.clear(); 138 | break; 139 | } 140 | Keyword.clear(); 141 | } 142 | else if(!FirstChar) 143 | { 144 | FirstChar = true; 145 | LastLine = Line; 146 | LastCharacter = Character; 147 | Keyword.push_back(EyeContent[x]); 148 | } 149 | else 150 | Keyword.push_back(EyeContent[x]); 151 | } 152 | else if(IsName) 153 | { 154 | if(EyeContent[x] == '\n' || EyeContent[x] == ' ') 155 | { 156 | IsName = false; 157 | FirstChar = false; 158 | if(Utilities::IsOnlyNumeric(Keyword)) 159 | { 160 | IsError = true; 161 | ep.Line = Line; 162 | ep.Character = Character; 163 | ep.Message = "The project name '" + Keyword + "' starting at " + to_string(LastLine) + " : " + to_string(LastCharacter) + ", is only numeric"; 164 | Keyword.clear(); 165 | break; 166 | } 167 | else 168 | Database::ProjectName = Keyword; 169 | Keyword.clear(); 170 | } 171 | else if(!Utilities::IsAlphanumeric(EyeContent[x])) 172 | { 173 | InvalidCharName = true; 174 | IsError = true; 175 | IsName = false; 176 | ep.Line = Line; 177 | ep.Character = Character; 178 | const string str(1, EyeContent[x]); 179 | if(!FirstChar) 180 | ep.Message = "The first character '" + str + "' of the project name is not alphanumeric. Valid characters on the actual context are '_', from '0' to '9', from 'A' to 'Z', and from 'a' to 'z'"; 181 | else 182 | ep.Message = "The character '" + str + "' of the project name starting at " + to_string(LastLine) + " : " + to_string(LastCharacter) + ", is not alphanumeric. Valid characters on the actual context are '_', from '0' to '9', from 'A' to 'Z', and from 'a' to 'z'"; 183 | Keyword.clear(); 184 | break; 185 | } 186 | else if(!FirstChar) 187 | { 188 | FirstChar = true; 189 | LastLine = Line; 190 | LastCharacter = Character; 191 | Keyword.push_back(EyeContent[x]); 192 | } 193 | else 194 | Keyword.push_back(EyeContent[x]); 195 | } 196 | else if(IsMeasureType) 197 | { 198 | if(EyeContent[x] == '\n' || EyeContent[x] == ' ') 199 | { 200 | FirstChar = false; 201 | IsMeasureType = false; 202 | const size_t h = Utilities::Hash(Keyword); 203 | if(h == Hashes::Nanoseconds) 204 | Database::mtp = MeasureTypes::Nanoseconds; 205 | else if(h == Hashes::Milliseconds) 206 | Database::mtp = MeasureTypes::Milliseconds; 207 | else if(h != Hashes::Microseconds) 208 | { 209 | IsMeasureType = false; 210 | IsError = true; 211 | ep.Line = Line; 212 | ep.Character = Character; 213 | ep.Message = "Wrong time-measurement type '" + Keyword + "' starting at " + to_string(LastLine) + " : " + to_string(LastCharacter) + ". Accepted commands are ms(milliseconds), mcs(microseconds), and ns(nanoseconds)"; 214 | Keyword.clear(); 215 | break; 216 | } 217 | Keyword.clear(); 218 | } 219 | else if(!FirstChar) 220 | { 221 | FirstChar = true; 222 | LastLine = Line; 223 | LastCharacter = Character; 224 | Keyword.push_back(EyeContent[x]); 225 | } 226 | else 227 | Keyword.push_back(EyeContent[x]); 228 | } 229 | else if(EyeContent[x] == '\n' || EyeContent[x] == ' ') 230 | { 231 | if(Keyword.size() > 0) 232 | { 233 | FirstChar = false; 234 | const size_t h = Utilities::Hash(Keyword); 235 | if(h == Hashes::Natlib) 236 | IsNatlib = true; 237 | else if(h == Hashes::IsConsole) 238 | Database::IsConsole = true; 239 | else if(h == Hashes::InitApp) 240 | Database::InitApp = true; 241 | else if(h == Hashes::Ignore) 242 | IsIgnore = true; 243 | else if(h == Hashes::UseVisualDebugger) 244 | Database::UseVisualDebugger = true; 245 | else if(h == Hashes::MeasureType) 246 | IsMeasureType = true; 247 | else if(h == Hashes::ReportPupil) 248 | Database::ReportPupil = true; 249 | else if(h == Hashes::Name) 250 | IsName = true; 251 | else if(h == Hashes::Type) 252 | IsType = true; 253 | else 254 | { 255 | IsError = true; 256 | ep.Line = Line; 257 | ep.Character = Character; 258 | ep.Message = "The keyword '" + Keyword + "' starting at " + to_string(LastLine) + " : " + to_string(LastCharacter) + " is unrecognized"; 259 | break; 260 | } 261 | Keyword.clear(); 262 | } 263 | } 264 | else if(!FirstChar) 265 | { 266 | FirstChar = true; 267 | LastLine = Line; 268 | LastCharacter = Character; 269 | Keyword.push_back(EyeContent[x]); 270 | } 271 | else 272 | Keyword.push_back(EyeContent[x]); 273 | } 274 | if(Keyword.size() > 0) 275 | { 276 | if(IsIgnore) 277 | { 278 | if(!Utilities::FileExists(Keyword)) 279 | { 280 | IsError = true; 281 | ep.Line = Line; 282 | ep.Character = Character; 283 | ep.Message = "The ignored iris file '" + Keyword + "' does not exists"; 284 | } 285 | else 286 | Database::IgnoredIris.push_back(Keyword); 287 | } 288 | else if(IsNatlib) 289 | { 290 | if(Utilities::FileExists(Keyword)) 291 | { 292 | bool Exists = false; 293 | size_t ExistingLine, ExistingCharacter; 294 | for(size_t xx = 0; xx < Database::NativeLibraries.size(); ++xx) 295 | if(Keyword == Database::NativeLibraries[xx].Name) 296 | { 297 | ExistingLine = Database::NativeLibraries[xx].Line; 298 | ExistingCharacter = Database::NativeLibraries[xx].Character; 299 | Exists = true; 300 | break; 301 | } 302 | if(!Exists) 303 | { 304 | lf.Line = LastLine; 305 | lf.Character = LastCharacter; 306 | lf.Name = Keyword; 307 | Database::NativeLibraries.push_back(lf); 308 | } 309 | else 310 | { 311 | IsError = true; 312 | ep.Line = Line; 313 | ep.Character = Character; 314 | ep.Message = "The native library declaration '" + Keyword + "' starting at " + to_string(LastLine) + " : " + to_string(LastCharacter) + " is already specified at " + to_string(ExistingLine) + " : " + to_string(ExistingCharacter); 315 | } 316 | } 317 | else 318 | { 319 | IsError = true; 320 | ep.Line = Line; 321 | ep.Character = Character; 322 | ep.Message = "The native library declaration '" + Keyword + "' starting at " + to_string(LastLine) + " : " + to_string(LastCharacter) + ", does not exists"; 323 | } 324 | } 325 | else if(IsType) 326 | { 327 | const size_t h = Utilities::Hash(Keyword); 328 | if(h == Hashes::Executable) 329 | Database::pt = ProjectType::Executable; 330 | else if(h == Hashes::Library) 331 | Database::pt = ProjectType::Library; 332 | else if(h != Hashes::Sandbox) 333 | { 334 | IsError = true; 335 | ep.Line = Line; 336 | ep.Character = Character; 337 | ep.Message = "The project type '" + Keyword + "' starting at " + to_string(LastLine) + " : " + to_string(LastCharacter) + ", is unrecognized"; 338 | } 339 | } 340 | else if(IsMeasureType) 341 | { 342 | const size_t h = Utilities::Hash(Keyword); 343 | if(h == Hashes::Nanoseconds) 344 | Database::mtp = MeasureTypes::Nanoseconds; 345 | else if(h == Hashes::Milliseconds) 346 | Database::mtp = MeasureTypes::Milliseconds; 347 | else if(h != Hashes::Microseconds) 348 | { 349 | IsError = true; 350 | ep.Line = Line; 351 | ep.Character = Character; 352 | ep.Message = "Wrong time-measurement type '" + Keyword + "' starting at " + to_string(LastLine) + " : " + to_string(LastCharacter) + ". Accepted commands are ms(milliseconds), mcs(microseconds), and ns(nanoseconds)"; 353 | } 354 | } 355 | else if(IsName) 356 | { 357 | if(Utilities::IsOnlyNumeric(Keyword)) 358 | { 359 | IsError = true; 360 | ep.Line = Line; 361 | ep.Character = Character; 362 | ep.Message = "The project name '" + Keyword + "' starting at " + to_string(LastLine) + " : " + to_string(LastCharacter) + ", is only numeric"; 363 | } 364 | else 365 | Database::ProjectName = Keyword; 366 | } 367 | else 368 | { 369 | const size_t h = Utilities::Hash(Keyword); 370 | if(h == Hashes::UseVisualDebugger) 371 | Database::UseVisualDebugger = true; 372 | else if(h == Hashes::ReportPupil) 373 | Database::ReportPupil = true; 374 | else if(h == Hashes::IsConsole) 375 | Database::IsConsole = true; 376 | else if(h == Hashes::InitApp) 377 | Database::InitApp = true; 378 | else 379 | { 380 | IsError = true; 381 | ep.Line = Line; 382 | ep.Character = Character; 383 | ep.Message = "The keyword '" + Keyword + "' starting at " + to_string(LastLine) + " : " + to_string(LastCharacter) + " is unrecognized"; 384 | } 385 | } 386 | } 387 | else if (IsType) 388 | { 389 | IsError = true; 390 | ep.Line = Line; 391 | ep.Character = Character; 392 | ep.Message = "Expected the project type specifier after the 'type' command starting at " + to_string(LastLine) + " : " + to_string(LastCharacter); 393 | } 394 | else if(IsIgnore) 395 | { 396 | IsError = true; 397 | ep.Line = Line; 398 | ep.Character = Character; 399 | ep.Message = "Expected the path of the ignored iris file after the 'ignore' specifier starting at " + to_string(LastLine) + " : " + to_string(LastCharacter); 400 | } 401 | else if(IsNatlib) 402 | { 403 | IsError = true; 404 | ep.Line = Line; 405 | ep.Character = Character; 406 | ep.Message = "Expected the path of a native library after the 'natlib' command starting at " + to_string(LastLine) + " : " + to_string(LastCharacter); 407 | } 408 | else if(IsMeasureType) 409 | { 410 | IsError = true; 411 | ep.Line = Line; 412 | ep.Character = Character; 413 | ep.Message = "Expected the type of time measurement after the 'measuretype' command starting at " + to_string(LastLine) + " : " + to_string(LastCharacter); 414 | } 415 | Database::IrisFiles = Utilities::GetFilesInFolder(Database::SourceFolder); 416 | Console::Append("Reading and parsing the eye project file took " + Utilities::TimeDiff(a, Utilities::TimePoint())); 417 | if(Database::ProjectName.size() == 0 && !InvalidCharName) 418 | Console::Append("\n\nError at '" + Database::ProjectPath + "' -> The project name is missing"); 419 | else if(IsError) 420 | Console::Append("\n\nError at '" + Database::ProjectPath + "', " + to_string(ep.Line) + " : " + to_string(ep.Character) + " -> " + ep.Message); 421 | else if(Database::IrisFiles.size() == 0) 422 | Console::Append("\n\nThere are no source files with .iris extension"); 423 | else 424 | { 425 | if(!Database::UseVisualDebugger) 426 | { 427 | if(Database::NativeLibraries.size() > 0) 428 | { 429 | thread t(Linker::Process); 430 | Pupil::Process(); 431 | t.join(); 432 | } 433 | else 434 | Pupil::Process(); 435 | if(!Database::LinkerError && !Database::PupilError) 436 | { 437 | Nerve::Process(); 438 | Console::Append("\n\nThe entire compilation took " + Utilities::TimeDiff(a, Utilities::TimePoint())); 439 | Utilities::WriteBinary(Database::OutputFolder + Database::ProjectName + ".exe", Database::Binary); 440 | } 441 | } 442 | else if(Database::NativeLibraries.size() > 0) 443 | { 444 | thread t(Linker::Process); 445 | thread tt(Pupil::Process); 446 | VisualDebugger::Start(); 447 | t.join(); 448 | tt.join(); 449 | if(!Database::LinkerError && !Database::PupilError) 450 | { 451 | Nerve::Process(); 452 | Console::Append("\n\nThe entire compilation took " + Utilities::TimeDiff(a, Utilities::TimePoint())); 453 | Utilities::WriteBinary(Database::OutputFolder + Database::ProjectName + ".exe", Database::Binary); 454 | } 455 | } 456 | else 457 | { 458 | thread t(Pupil::Process); 459 | VisualDebugger::Start(); 460 | t.join(); 461 | if(!Database::PupilError) 462 | { 463 | Nerve::Process(); 464 | Console::Append("\n\nThe entire compilation took " + Utilities::TimeDiff(a, Utilities::TimePoint())); 465 | Utilities::WriteBinary(Database::OutputFolder + Database::ProjectName + ".exe", Database::Binary); 466 | } 467 | } 468 | } 469 | if(Database::ReportPupil) 470 | Pupil::Report(); 471 | Database::LastMessage = true; 472 | } 473 | } 474 | } -------------------------------------------------------------------------------- /Iris.cpp: -------------------------------------------------------------------------------- 1 | //Copyright 2020 Iris Technologies, All Rights Reserved 2 | #pragma once 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | void Execute() noexcept 10 | { 11 | system("cls");//I know, i know, it won't be on the final version, it's just that i didn't make the Win32 function work, and 12 | //i had some other priorities, so i just leave that by now, don't blame me too much 13 | thread t(ProjectIris::Eye::Process); 14 | bool Exit = false; 15 | while (!Exit) 16 | { 17 | this_thread::sleep_for(chrono::milliseconds(200)); 18 | if (ProjectIris::Database::LastMessage) 19 | Exit = true; 20 | } 21 | ProjectIris::Utilities::Recompile(); 22 | } 23 | 24 | int main(int argc, char** argv) 25 | { 26 | system("cls"); 27 | HWND console = GetConsoleWindow(); 28 | RECT r; 29 | GetWindowRect(console, &r); 30 | MoveWindow(console, r.left, r.top, 1200, 600, TRUE); 31 | SetConsoleTitle("Alice"); 32 | HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); 33 | SetConsoleTextAttribute(hStdOut, 11 | FOREGROUND_INTENSITY); 34 | const string e1("Wrong number of arguments!"); 35 | if (argc == 3) 36 | { 37 | const string cmd(argv[1]); 38 | const string s(argv[2]); 39 | const string e2("The file '" + s + "' does not exists!"); 40 | if(cmd == "compile") 41 | { 42 | if(ProjectIris::Utilities::FileExists(s)) 43 | { 44 | const string base = ProjectIris::Utilities::GetDirectory(s) + "\\"; 45 | const string src = base + "src"; 46 | const string out = base + "output"; 47 | const string e3("The source folder '" + src + "' does not exists!"); 48 | const string e4("The output folder '" + out + "' does not exists!"); 49 | if(!ProjectIris::Utilities::DirectoryExists(src)) 50 | std::cout << e3 << std::endl; 51 | else if(!ProjectIris::Utilities::DirectoryExists(out)) 52 | std::cout << e4 << std::endl; 53 | else 54 | { 55 | ProjectIris::Database::ProjectSourceLength = src.size() + 1; 56 | ProjectIris::Database::ProjectPath = s; 57 | ProjectIris::Database::SourceFolder = src; 58 | ProjectIris::Database::OutputFolder = out + "\\"; 59 | Execute(); 60 | } 61 | } 62 | else 63 | std::cout << e2 << std::endl; 64 | } 65 | } 66 | else 67 | std::cout << e1 << std::endl; 68 | char c; 69 | std::cin >> c; 70 | return 0; 71 | } 72 | -------------------------------------------------------------------------------- /Iris.hpp: -------------------------------------------------------------------------------- 1 | //Copyright 2020 Iris Technologies, All Rights Reserved 2 | #pragma once 3 | 4 | void Execute() noexcept; -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright by Iris Technologies (c) 2020 Project Iris 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Linker.hpp: -------------------------------------------------------------------------------- 1 | //Copyright 2020 Iris Technologies, All Rights Reserved 2 | #pragma once 3 | #include 4 | 5 | namespace ProjectIris 6 | { 7 | namespace Linker 8 | { 9 | __forceinline void Process() noexcept 10 | { 11 | if(Database::os == OperatingSystem::Windows) 12 | PE::ReadExportedSymbols(); 13 | } 14 | 15 | __forceinline void LinkPE() noexcept 16 | { 17 | const chrono::steady_clock::time_point a = Utilities::TimePoint(); 18 | unsigned short NumberOfSections = static_cast(1); 19 | PE::FillToFitFileAlignment(static_cast(40)); 20 | Database::Binary.insert(Database::Binary.end(), Database::Text.begin(), Database::Text.end()); 21 | unsigned int SizeOfCode = static_cast(Database::Text.size()); 22 | SizeOfCode = PE::RoundToLineAlignment(SizeOfCode); 23 | PE::FillToFitFileAlignment(SizeOfCode); 24 | unsigned int VSizeOfCode = PE::RoundToFileAlignment(SizeOfCode); 25 | PE::WriteTextSectionSize(SizeOfCode, VSizeOfCode); 26 | PE::WriteNumberOfSections(NumberOfSections); 27 | PE::WriteSizeOfCode(VSizeOfCode); 28 | PE::WriteOSVersions(); 29 | PE::WriteAppVersions(); 30 | PE::WriteTimeStamp(); 31 | PE::WriteSubsystem(); 32 | PE::WriteSizeOfApp(); 33 | const chrono::steady_clock::time_point b = Utilities::TimePoint(); 34 | Console::Append("\n\nLinking the executable took " + Utilities::TimeDiff(a, b)); 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /Nerve.hpp: -------------------------------------------------------------------------------- 1 | //Copyright 2020 Iris Technologies, All Rights Reserved 2 | #pragma once 3 | #include 4 | #include 5 | 6 | namespace ProjectIris 7 | { 8 | namespace Nerve 9 | { 10 | //Source Register values -> 0 = nothing, 1 = al 11 | //Destination Register(Future use) values -> 0 = nothing, 1 = al 12 | 13 | __forceinline void Process() noexcept 14 | { 15 | vector Registers; 16 | RegisterAliasing ra; 17 | size_t VarSize = 0; 18 | bool BusyAl = false;//Indicates if 'al' register is being used 19 | for(size_t x = 0; x < Database::PupilFInstructions.size(); ++x) 20 | { 21 | if(Database::PupilFInstructions[x].Opcode == Opcodes::LocalVariableType) 22 | { 23 | if(Database::PupilFInstructions[x].Name == Hashes::S8) 24 | VarSize = 8; 25 | } 26 | else if(Database::PupilFInstructions[x].Opcode == Opcodes::LocalVariableName) 27 | { 28 | if(VarSize == 8) 29 | { 30 | if(!BusyAl)//al register isn't being used so we can alias the name 31 | { 32 | BusyAl = true; 33 | ra.VarName = Database::PupilFInstructions[x].Name; 34 | ra.Register = 1; 35 | Registers.push_back(ra); 36 | } 37 | } 38 | } 39 | else if(Database::PupilFInstructions[x].Opcode == Opcodes::EqualOperation) 40 | { 41 | size_t ActualRegisterAliasing = 0; 42 | for(size_t y = 0; y < Registers.size(); ++y) 43 | if(Database::PupilFInstructions[x - 1].Name == Registers[y].VarName) 44 | { 45 | ActualRegisterAliasing = y; 46 | break; 47 | } 48 | if(Registers[ActualRegisterAliasing].Register == 1 && Database::PupilFInstructions[x + 1].IsLiteral) 49 | { 50 | Database::Text.push_back(X64::Mov8ImmToAl); 51 | Database::Text.push_back(static_cast(Database::PupilFInstructions[x + 1].Name)); 52 | Registers.erase(Registers.begin() + ActualRegisterAliasing); 53 | } 54 | } 55 | } 56 | if(Database::os == OperatingSystem::Windows || Database::os == OperatingSystem::Xbox) 57 | Linker::LinkPE(); 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /PE.hpp: -------------------------------------------------------------------------------- 1 | //Copyright 2020 Iris Technologies, All Rights Reserved 2 | #pragma once 3 | #include 4 | #include 5 | #include 6 | 7 | namespace ProjectIris 8 | { 9 | namespace PE 10 | { 11 | constexpr unsigned long long ImageBase64 = 4194304; 12 | 13 | constexpr unsigned int ImageBase32 = 4194304; 14 | 15 | __forceinline unsigned int CalculateSectionVA(const unsigned int SizeOfLastSection, const unsigned int VAOfLastSection) noexcept 16 | { 17 | return VAOfLastSection + (SizeOfLastSection / 4096 + 1) * 4096; 18 | } 19 | 20 | __forceinline void WriteNumberOfSections(const unsigned short number) noexcept 21 | { 22 | Bytes2 b = Utilities::UshortToBytes(number); 23 | Database::Binary[254] = b.b; 24 | Database::Binary[255] = b.a; 25 | } 26 | 27 | __forceinline void WriteTimeStamp() noexcept 28 | { 29 | Bytes4 b = Utilities::UintToBytes(static_cast(chrono::duration_cast(chrono::system_clock::now().time_since_epoch()).count())); 30 | Database::Binary[256] = b.d; 31 | Database::Binary[257] = b.c; 32 | Database::Binary[258] = b.b; 33 | Database::Binary[259] = b.a; 34 | } 35 | 36 | __forceinline void WriteSizeOfCode(const unsigned int size) noexcept 37 | { 38 | Bytes4 b = Utilities::UintToBytes(size); 39 | Database::Binary[276] = b.d; 40 | Database::Binary[277] = b.c; 41 | Database::Binary[278] = b.b; 42 | Database::Binary[279] = b.a; 43 | } 44 | 45 | __forceinline void WriteSizeOfRdataAndData(const unsigned int size) noexcept 46 | { 47 | Bytes4 b = Utilities::UintToBytes(size); 48 | Database::Binary[280] = b.d; 49 | Database::Binary[281] = b.c; 50 | Database::Binary[282] = b.b; 51 | Database::Binary[283] = b.a; 52 | } 53 | 54 | __forceinline void WriteSizeOfBss(const unsigned int size) noexcept 55 | { 56 | Bytes4 b = Utilities::UintToBytes(size); 57 | Database::Binary[284] = b.d; 58 | Database::Binary[285] = b.c; 59 | Database::Binary[286] = b.d; 60 | Database::Binary[287] = b.a; 61 | } 62 | 63 | __forceinline void WriteOSVersions() noexcept 64 | { 65 | Bytes2 b = Utilities::UshortToBytes(Database::MajorWindowsVersion); 66 | Database::Binary[312] = b.b; 67 | Database::Binary[313] = b.a; 68 | Database::Binary[320] = b.b; 69 | Database::Binary[321] = b.a; 70 | b = Utilities::UshortToBytes(Database::MinorWindowsVersion); 71 | Database::Binary[314] = b.b; 72 | Database::Binary[315] = b.a; 73 | Database::Binary[322] = b.b; 74 | Database::Binary[323] = b.a; 75 | } 76 | 77 | __forceinline void WriteAppVersions() noexcept 78 | { 79 | Bytes2 b = Utilities::UshortToBytes(Database::MajorAppVersion); 80 | Database::Binary[316] = b.b; 81 | Database::Binary[317] = b.a; 82 | b = Utilities::UshortToBytes(Database::MinorAppVersion); 83 | Database::Binary[318] = b.b; 84 | Database::Binary[319] = b.a; 85 | } 86 | 87 | __forceinline void WriteSizeOfApp() noexcept 88 | { 89 | const size_t s = Database::NativeSections.size() - 1; 90 | Bytes4 b = Utilities::UintToBytes(((Database::NativeSections[s].VirtualAddress + (Database::NativeSections[s].VirtualAddress + Database::NativeSections[s].VirtualSize) - Database::NativeSections[s].PointerToRawData) / 4096 + 1) * 4096); 91 | Database::Binary[328] = b.d; 92 | Database::Binary[329] = b.c; 93 | Database::Binary[330] = b.b; 94 | Database::Binary[331] = b.a; 95 | } 96 | 97 | __forceinline void WriteSubsystem() noexcept 98 | { 99 | if(Database::os == OperatingSystem::Xbox) 100 | Database::Binary[340] = 0xe; 101 | else if(Database::IsConsole) 102 | Database::Binary[340] = 3; 103 | else 104 | Database::Binary[340] = 2; 105 | } 106 | 107 | __forceinline void WriteSizeOfReservedStack(const unsigned long long size) noexcept 108 | { 109 | Bytes8 b = Utilities::UlongToBytes(size); 110 | Database::Binary[344] = b.h; 111 | Database::Binary[345] = b.g; 112 | Database::Binary[346] = b.f; 113 | Database::Binary[347] = b.e; 114 | Database::Binary[348] = b.d; 115 | Database::Binary[349] = b.c; 116 | Database::Binary[350] = b.b; 117 | Database::Binary[351] = b.a; 118 | } 119 | 120 | __forceinline void WriteSizeOfCommitStack(const unsigned long long size) noexcept 121 | { 122 | Bytes8 b = Utilities::UlongToBytes(size); 123 | Database::Binary[352] = b.h; 124 | Database::Binary[353] = b.g; 125 | Database::Binary[354] = b.f; 126 | Database::Binary[355] = b.e; 127 | Database::Binary[356] = b.d; 128 | Database::Binary[357] = b.c; 129 | Database::Binary[358] = b.b; 130 | Database::Binary[359] = b.a; 131 | } 132 | 133 | __forceinline void WriteSizeOfReservedHeap(const unsigned long long size) noexcept 134 | { 135 | Bytes8 b = Utilities::UlongToBytes(size); 136 | Database::Binary[360] = b.h; 137 | Database::Binary[361] = b.g; 138 | Database::Binary[362] = b.f; 139 | Database::Binary[363] = b.e; 140 | Database::Binary[364] = b.d; 141 | Database::Binary[365] = b.c; 142 | Database::Binary[366] = b.b; 143 | Database::Binary[367] = b.a; 144 | } 145 | 146 | __forceinline void WriteSizeOfCommitHeap(const unsigned long long size) noexcept 147 | { 148 | Bytes8 b = Utilities::UlongToBytes(size); 149 | Database::Binary[368] = b.h; 150 | Database::Binary[369] = b.g; 151 | Database::Binary[370] = b.f; 152 | Database::Binary[371] = b.e; 153 | Database::Binary[372] = b.d; 154 | Database::Binary[373] = b.c; 155 | Database::Binary[374] = b.b; 156 | Database::Binary[375] = b.a; 157 | } 158 | 159 | __forceinline unsigned int RoundToLineAlignment(const unsigned int size) noexcept 160 | { 161 | if(size % static_cast(16) == 0) 162 | return size; 163 | else 164 | return (size / static_cast(16) + static_cast(1)) * static_cast(16); 165 | } 166 | 167 | __forceinline unsigned int RoundToFileAlignment(const unsigned int size) noexcept 168 | { 169 | if(size % static_cast(512) == 0) 170 | return size; 171 | else 172 | return (size / static_cast(512) + static_cast(1)) * static_cast(512); 173 | } 174 | 175 | __forceinline unsigned int RoundFileToMemoryAlignment(const unsigned int size) noexcept 176 | { 177 | if(size % static_cast(512) == 0) 178 | return size / 512 * 4096; 179 | else 180 | return (size / static_cast(512) + static_cast(1)) * static_cast(4096); 181 | } 182 | 183 | __forceinline size_t RoundToMemoryAlignment(const size_t size) noexcept 184 | { 185 | return (size / static_cast(4096) + static_cast(1)) * static_cast(4096); 186 | } 187 | 188 | __forceinline void FillToFitFileAlignment(const size_t size) noexcept 189 | { 190 | const size_t RTFA = RoundToFileAlignment(size); 191 | if(RTFA != size) 192 | Database::Binary.resize(Database::Binary.size() + (RTFA - size)); 193 | } 194 | 195 | __forceinline void WriteTextSection() noexcept 196 | { 197 | PENativeSection text; 198 | text.PointerToRawData = static_cast(1024); 199 | text.VirtualAddress = static_cast(4096); 200 | text.SizeOfRawData = static_cast(0); 201 | text.VirtualSize = static_cast(0); 202 | Database::NativeSections.push_back(text); 203 | } 204 | 205 | __forceinline void WriteTextSectionSize(const unsigned int size, const unsigned int roundedsize) noexcept 206 | { 207 | Database::NativeSections[0].VirtualSize = size; 208 | Database::NativeSections[0].SizeOfRawData = roundedsize; 209 | Bytes4 b = Utilities::UintToBytes(roundedsize); 210 | Database::Binary[528] = b.d; 211 | Database::Binary[529] = b.c; 212 | Database::Binary[530] = b.b; 213 | Database::Binary[531] = b.a; 214 | b = Utilities::UintToBytes(size); 215 | Database::Binary[520] = b.d; 216 | Database::Binary[521] = b.c; 217 | Database::Binary[522] = b.b; 218 | Database::Binary[523] = b.a; 219 | } 220 | 221 | __forceinline unsigned int RVAToFileOffset(const vector& Sections, const unsigned int RVA) noexcept 222 | { 223 | size_t SectionOffset = 0; 224 | for(; SectionOffset < Sections.size(); ++SectionOffset) 225 | if(RVA >= Sections[SectionOffset].VirtualAddress && RVA < Sections[SectionOffset].VirtualEnd) 226 | break; 227 | return RVA - Sections[SectionOffset].VirtualAddress + Sections[SectionOffset].PointerToRawData; 228 | } 229 | 230 | __forceinline void ReadExportedSymbols() noexcept 231 | { 232 | for(size_t x = 0; x < Database::NativeLibraries.size(); ++x) 233 | { 234 | const chrono::steady_clock::time_point a = Utilities::TimePoint(); 235 | const vector Content = Utilities::ReadBinary(Database::NativeLibraries[x].Name); 236 | if(Content[0] == 0x4d && Content[1] == 0x5a) 237 | { 238 | unsigned int Offset = Utilities::BytesToUint(Content[60], Content[61], Content[62], Content[63]); 239 | if(Content[Offset] == 0x50 && Content[Offset + 1] == 0x45 && Content[Offset + 2] == 0 && Content[Offset + 3] == 0) 240 | { 241 | unsigned short NumberOfSections = Utilities::BytesToUshort(Content[Offset + 6], Content[Offset + 7]); 242 | unsigned int ExportRVA; 243 | if(Content[Offset + 25] == 2) 244 | { 245 | ExportRVA = Utilities::BytesToUint(Content[Offset + 136], Content[Offset + 137], Content[Offset + 138], Content[Offset + 139]); 246 | Offset += 272; 247 | } 248 | else 249 | { 250 | ExportRVA = Utilities::BytesToUint(Content[Offset + 120], Content[Offset + 121], Content[Offset + 122], Content[Offset + 123]); 251 | Offset += 256; 252 | } 253 | if(ExportRVA == 0) 254 | { 255 | Console::LinkerError("\n\nThe native library '" + Database::NativeLibraries[x].Name + "' does not contain any export table"); 256 | break; 257 | } 258 | else 259 | { 260 | vector Sections(NumberOfSections); 261 | for(unsigned short us = 0; us < NumberOfSections; ++us, Offset += 40) 262 | { 263 | PESection pes; 264 | unsigned int VirtualSize = Utilities::BytesToUint(Content[Offset], Content[Offset + 1], Content[Offset + 2], Content[Offset + 3]); 265 | pes.VirtualAddress = Utilities::BytesToUint(Content[Offset + 4], Content[Offset + 5], Content[Offset + 6], Content[Offset + 7]); 266 | pes.VirtualEnd = pes.VirtualAddress + VirtualSize; 267 | pes.PointerToRawData = Utilities::BytesToUint(Content[Offset + 12], Content[Offset + 13], Content[Offset + 14], Content[Offset + 15]); 268 | Sections[us] = pes; 269 | } 270 | Offset = RVAToFileOffset(Sections, ExportRVA) + 20; 271 | const unsigned int ESS = static_cast(Database::ExportedSymbols.size()); 272 | unsigned int NumberOfFunctions = ESS + Utilities::BytesToUint(Content[Offset], Content[Offset + 1], Content[Offset + 2], Content[Offset + 3]); 273 | Database::ExportedSymbols.resize(NumberOfFunctions); 274 | Offset = RVAToFileOffset(Sections, Utilities::BytesToUint(Content[Offset + 12], Content[Offset + 13], Content[Offset + 14], Content[Offset + 15])); 275 | for(unsigned int i = ESS; i < NumberOfFunctions; ++i, Offset += 4) 276 | { 277 | string Name; 278 | unsigned int NameOffset = RVAToFileOffset(Sections, Utilities::BytesToUint(Content[Offset], Content[Offset + 1], Content[Offset + 2], Content[Offset + 3])); 279 | while(Content[NameOffset] != 0) 280 | { 281 | Name.push_back(static_cast(Content[NameOffset])); 282 | ++NameOffset; 283 | } 284 | Database::ExportedSymbols[i] = Utilities::Hash(Demangler::Demangle(Name)); 285 | } 286 | } 287 | } 288 | else 289 | { 290 | Console::LinkerError("\n\nThe native library '" + Database::NativeLibraries[x].Name + "' does not have any PE\\0\\0 signature"); 291 | break; 292 | } 293 | } 294 | else 295 | { 296 | Console::LinkerError("\n\nThe native library '" + Database::NativeLibraries[x].Name + "' does not have any MZ signature"); 297 | break; 298 | } 299 | const chrono::steady_clock::time_point b = Utilities::TimePoint(); 300 | Console::Append("\n\nReading and extracting the exported symbols of the native library '" + Database::NativeLibraries[x].Name + "' took " + Utilities::TimeDiff(a, b)); 301 | } 302 | } 303 | } 304 | } -------------------------------------------------------------------------------- /Pupil.hpp: -------------------------------------------------------------------------------- 1 | //Copyright 2020 Iris Technologies, All Rights Reserved 2 | #pragma once 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace ProjectIris 9 | { 10 | namespace Pupil 11 | { 12 | __forceinline void Report() noexcept 13 | { 14 | string Output("New file " + Database::PupilFiles[0]); 15 | for(size_t x = 1; x < Database::PupilFInstructions.size(); ++x) 16 | switch (Database::PupilFInstructions[x].Opcode) 17 | { 18 | case Opcodes::NewFile: 19 | Output.append("\n\nNew file " + Database::PupilFiles[Database::PupilFInstructions[x].Name]); 20 | break; 21 | case Opcodes::StartModule: 22 | Output.append("\n\nStart module '" + to_string(Database::PupilFInstructions[x].Name) + "'"); 23 | break; 24 | case Opcodes::EndModule: 25 | Output.append("\n\nEnd module '" + to_string(Database::PupilFInstructions[x].Name) + "'"); 26 | break; 27 | case Opcodes::StartFunction: 28 | Output.append("\n\nStart function '" + to_string(Database::PupilFInstructions[x].Name) + "'"); 29 | break; 30 | case Opcodes::InArgument: 31 | Output.append("\n\nInput argument of type '"); 32 | break; 33 | case Opcodes::InoutArgument: 34 | Output.append("\n\nInput/output argument of type '"); 35 | break; 36 | case Opcodes::OutArgument: 37 | Output.append("\n\nOutput argument of type '"); 38 | break; 39 | case Opcodes::ArgumentType: 40 | Output.append(to_string(Database::PupilFInstructions[x].Name) + "' with name '"); 41 | break; 42 | case Opcodes::ArgumentName: 43 | Output.append(to_string(Database::PupilFInstructions[x].Name) + "'"); 44 | break; 45 | case Opcodes::Main: 46 | Output.append("\n\nStarting main function..."); 47 | break; 48 | case Opcodes::FunctionBody: 49 | Output.append("\n\nStarting function body..."); 50 | break; 51 | case Opcodes::EndFunction: 52 | Output.append("\n\nEnding function"); 53 | break; 54 | case Opcodes::LocalVariableType: 55 | Output.append("\n\nVariable type: " + to_string(Database::PupilFInstructions[x].Name) + ", Variable name: "); 56 | break; 57 | case Opcodes::LocalVariableName: 58 | Output.append(to_string(Database::PupilFInstructions[x].Name)); 59 | break; 60 | case Opcodes::LvalueKeyword: 61 | Output.append("\n\nLvalue keyword '" + to_string(Database::PupilFInstructions[x].Name) + "' "); 62 | break; 63 | case Opcodes::EqualOperation: 64 | Output.append("is equal to Rvalue keyword '"); 65 | break; 66 | case Opcodes::RvalueKeyword: 67 | Output.append(to_string(Database::PupilFInstructions[x].Name) + "'"); 68 | break; 69 | case Opcodes::Using: 70 | Output.append("\n\nUsing directive '" + to_string(Database::PupilFInstructions[x].Name) + "'"); 71 | break; 72 | } 73 | Utilities::WriteFile(Database::OutputFolder + Database::ProjectName + ".pupil", Output); 74 | } 75 | 76 | __forceinline void Process() noexcept 77 | { 78 | PupilFInstruction ins; 79 | for(size_t x = 0; x < Database::IrisFiles.size(); ++x) 80 | { 81 | string Name = Database::IrisFiles[x]; 82 | Name.erase(0, Database::ProjectSourceLength); 83 | if(Database::UseVisualDebugger && !Database::PupilError) 84 | Database::ActualFile = Name; 85 | Database::PupilFiles.push_back(Name); 86 | ins.Opcode = Opcodes::NewFile; 87 | Database::PupilFInstructions.push_back(ins); 88 | string Keyword, Modules; 89 | size_t Line = 1, Character = 0, LastLine, LastCharacter, ModuleCount = 0, ActualModule = 0, FunctionNode = 0, LvalueHash = 0, SleepTime = 0, ActualClass, MainFile, MainLine, MainCharacter; 90 | char Mode = 0; 91 | bool UseVDBG = Database::UseVisualDebugger, FirstChar = false, FirstSpace = false, IsModule = false, IsFunction = false, IsFunctionArguments = false, IsFunctionBody = false, IsLocalVariableDeclaration = true, IsMacro = false, IsSlowdown = false, IsUsing = false, IsClass = false, IsMain = false, MainFound = false; 92 | chrono::steady_clock::time_point a = Utilities::TimePoint(); 93 | const string Content = Utilities::ReadFile(Database::IrisFiles[x]); 94 | for(size_t i = 0; i < Content.size(); ++i) 95 | { 96 | if(SleepTime != 0) 97 | this_thread::sleep_for(chrono::milliseconds(SleepTime)); 98 | if(Content[i] == '\n') 99 | { 100 | if(UseVDBG) 101 | { 102 | ++Database::ActualLine; 103 | Database::ActualCharacter = 0; 104 | } 105 | ++Line; 106 | Character = 0; 107 | } 108 | else 109 | { 110 | if(UseVDBG) 111 | ++Database::ActualCharacter; 112 | ++Character; 113 | } 114 | if(IsFunctionBody) 115 | { 116 | if(Content[i] == '}') 117 | { 118 | if(FunctionNode == 0) 119 | { 120 | FirstSpace = false; 121 | IsLocalVariableDeclaration = true; 122 | IsFunctionBody = false; 123 | ins.Opcode = Opcodes::EndFunction; 124 | Database::PupilFInstructions.push_back(ins); 125 | } 126 | else 127 | --FunctionNode; 128 | } 129 | //I know it is bad but i just wanted to have something to do the backend, it will be refactored 130 | else if(Content[i] == ';') 131 | { 132 | if(Keyword.size() > 0) 133 | { 134 | if(!IsLocalVariableDeclaration) 135 | { 136 | FirstSpace = false; 137 | if (Utilities::nIsOnlyNumeric(Keyword.c_str(), Keyword.size())) 138 | { 139 | stringstream ss(Keyword); 140 | ss >> ins.Name; 141 | ins.IsLiteral = true; 142 | } 143 | else 144 | ins.Name = Utilities::Hash(Keyword); 145 | Keyword.clear(); 146 | ins.Opcode = Opcodes::RvalueKeyword; 147 | Database::PupilFInstructions.push_back(ins); 148 | } 149 | else if(FirstSpace) 150 | { 151 | FirstSpace = false; 152 | ins.Name = LvalueHash; 153 | LvalueHash = 0; 154 | ins.Opcode = Opcodes::LocalVariableType; 155 | Database::PupilFInstructions.push_back(ins); 156 | ins.Name = Utilities::Hash(Keyword); 157 | Keyword.clear(); 158 | ins.Opcode = Opcodes::LocalVariableName; 159 | Database::PupilFInstructions.push_back(ins); 160 | } 161 | } 162 | } 163 | else if(Content[i] == '=') 164 | { 165 | if(Keyword.size() > 0) 166 | { 167 | IsLocalVariableDeclaration = false; 168 | ins.Name = Utilities::Hash(Keyword); 169 | Keyword.clear(); 170 | ins.Opcode = Opcodes::LvalueKeyword; 171 | Database::PupilFInstructions.push_back(ins); 172 | ins.Opcode = Opcodes::EqualOperation; 173 | Database::PupilFInstructions.push_back(ins); 174 | } 175 | else if(LvalueHash != 0) 176 | { 177 | IsLocalVariableDeclaration = false; 178 | ins.Name = LvalueHash; 179 | LvalueHash = 0; 180 | ins.Opcode = Opcodes::LvalueKeyword; 181 | Database::PupilFInstructions.push_back(ins); 182 | ins.Opcode = Opcodes::EqualOperation; 183 | Database::PupilFInstructions.push_back(ins); 184 | } 185 | else 186 | { 187 | const string msg("The lvalue is missing"); 188 | Utilities::Report(Name, Line, Character, msg); 189 | break; 190 | } 191 | } 192 | else if(Content[i] != ' ' && Content[i] != '\n') 193 | { 194 | if(!Utilities::IsAlphanumeric(Content[i])) 195 | { 196 | const string c(1, Content[i]); 197 | const string msg("The character '" + c + "' is invalid"); 198 | Utilities::Report(Name, Line, Character, msg); 199 | break; 200 | } 201 | else if(!FirstChar) 202 | { 203 | FirstChar = true; 204 | LastLine = Line; 205 | LastCharacter = Character; 206 | Keyword.push_back(Content[i]); 207 | } 208 | else 209 | Keyword.push_back(Content[i]); 210 | } 211 | else if(Keyword.size() > 0 && !FirstSpace) 212 | { 213 | FirstSpace = true; 214 | LvalueHash = Utilities::Hash(Keyword); 215 | Keyword.clear(); 216 | } 217 | } 218 | else if(IsFunctionArguments) 219 | { 220 | if(Content[i] == '{') 221 | { 222 | if(FirstSpace) 223 | { 224 | FirstSpace = false; 225 | FirstChar = false; 226 | IsFunctionArguments = false; 227 | IsFunctionBody = true; 228 | ins.Opcode = Opcodes::FunctionBody; 229 | Database::PupilFInstructions.push_back(ins); 230 | } 231 | else 232 | { 233 | const string msg("Expected ')' before '{'"); 234 | Utilities::Report(Name, Line, Character, msg); 235 | break; 236 | } 237 | } 238 | else if(Content[i] == ' ' || Content[i] == '\n') 239 | { 240 | if(Keyword.size() > 0) 241 | { 242 | if(Mode == 0) 243 | { 244 | ++Mode; 245 | FirstChar = false; 246 | const size_t h = Utilities::Hash(Keyword); 247 | Keyword.clear(); 248 | if(h == Hashes::In) 249 | { 250 | ins.Opcode = Opcodes::InArgument; 251 | Database::PupilFInstructions.push_back(ins); 252 | } 253 | else if(h == Hashes::Inout) 254 | { 255 | ins.Opcode = Opcodes::InoutArgument; 256 | Database::PupilFInstructions.push_back(ins); 257 | } 258 | else if(h == Hashes::Out) 259 | { 260 | ins.Opcode = Opcodes::OutArgument; 261 | Database::PupilFInstructions.push_back(ins); 262 | } 263 | else 264 | { 265 | const string msg("Invalid argument direction '" + Keyword + "' starting at " + to_string(LastLine) + " : " + Utilities::to_stringc(LastCharacter) + ". Valid argument directions are 'in', 'inout', and 'out'"); 266 | Utilities::Report(Name, Line, Character, msg); 267 | break; 268 | } 269 | } 270 | else if(Mode == 1) 271 | { 272 | ++Mode; 273 | FirstChar = false; 274 | ins.Name = Utilities::Hash(Keyword); 275 | Keyword.clear(); 276 | ins.Line = LastLine; 277 | ins.Character = LastCharacter; 278 | ins.Opcode = Opcodes::ArgumentType; 279 | Database::PupilFInstructions.push_back(ins); 280 | } 281 | else if(Mode == 2) 282 | { 283 | if(Utilities::nIsOnlyNumeric(Keyword.c_str(), Keyword.size())) 284 | { 285 | const string msg("The argument name '" + Keyword + "' starting at " + to_string(LastLine) + " : " + Utilities::to_stringc(LastCharacter) + " is only numeric"); 286 | Utilities::Report(Name, Line, Character, msg); 287 | break; 288 | } 289 | else 290 | { 291 | ++Mode; 292 | ins.Name = Utilities::Hash(Keyword); 293 | Keyword.clear(); 294 | ins.Line = LastLine; 295 | ins.Character = LastCharacter; 296 | ins.Opcode = Opcodes::ArgumentName; 297 | Database::PupilFInstructions.push_back(ins); 298 | } 299 | } 300 | } 301 | } 302 | else if(FirstSpace) 303 | { 304 | const string msg("Expected '{'"); 305 | Utilities::Report(Name, Line, Character, msg); 306 | break; 307 | } 308 | else if(Content[i] == ',') 309 | { 310 | if(Mode == 3) 311 | Mode = 0; 312 | else if(Mode == 2) 313 | { 314 | if(Keyword.size() > 0) 315 | { 316 | if(Utilities::nIsOnlyNumeric(Keyword.c_str(), Keyword.size())) 317 | { 318 | const string msg("The argument name '" + Keyword + "' starting at " + to_string(LastLine) + " : " + Utilities::to_stringc(LastCharacter) + " is only numeric"); 319 | Utilities::Report(Name, Line, Character, msg); 320 | break; 321 | } 322 | else 323 | { 324 | Mode = 0; 325 | ins.Name = Utilities::Hash(Keyword); 326 | Keyword.clear(); 327 | ins.Opcode = Opcodes::ArgumentName; 328 | Database::PupilFInstructions.push_back(ins); 329 | } 330 | } 331 | else 332 | { 333 | const string msg("Expected the argument name after the argument type and before ','"); 334 | Utilities::Report(Name, Line, Character, msg); 335 | break; 336 | } 337 | } 338 | else if(Mode == 1) 339 | { 340 | const string msg("Expected the argument type after the argument direction and before ','"); 341 | Utilities::Report(Name, Line, Character, msg); 342 | break; 343 | } 344 | else 345 | { 346 | const string msg("Expected the argument direction before ','"); 347 | Utilities::Report(Name, Line, Character, msg); 348 | break; 349 | } 350 | } 351 | else if(Content[i] == ')') 352 | { 353 | if(Mode == 3) 354 | { 355 | Mode = 0; 356 | FirstSpace = true; 357 | } 358 | else if(Mode == 2) 359 | { 360 | if(Keyword.size() > 0) 361 | { 362 | if(Utilities::nIsOnlyNumeric(Keyword.c_str(), Keyword.size())) 363 | { 364 | const string msg("The argument name '" + Keyword + "' starting at " + to_string(LastLine) + " : " + Utilities::to_stringc(LastCharacter) + " is only numeric"); 365 | Utilities::Report(Name, Line, Character, msg); 366 | break; 367 | } 368 | else 369 | { 370 | Mode = 0; 371 | FirstSpace = true; 372 | ins.Name = Utilities::Hash(Keyword); 373 | Keyword.clear(); 374 | ins.Opcode = Opcodes::ArgumentName; 375 | Database::PupilFInstructions.push_back(ins); 376 | } 377 | } 378 | else 379 | { 380 | const string msg("Expected the argument name after the argument type and before ')'"); 381 | Utilities::Report(Name, Line, Character, msg); 382 | break; 383 | } 384 | } 385 | else if(Mode == 1) 386 | { 387 | const string msg("Expected the argument type after the argument direction and before ')'"); 388 | Utilities::Report(Name, Line, Character, msg); 389 | break; 390 | } 391 | else 392 | FirstSpace = true; 393 | } 394 | else if(!FirstChar) 395 | { 396 | FirstChar = true; 397 | LastLine = Line; 398 | LastCharacter = Character; 399 | Keyword.push_back(Content[i]); 400 | } 401 | else 402 | Keyword.push_back(Content[i]); 403 | } 404 | else if(IsFunction) 405 | { 406 | if(Content[i] == '(') 407 | { 408 | if(Utilities::nIsOnlyNumeric(Keyword.c_str(), Keyword.size())) 409 | { 410 | const string msg("The function name '" + Keyword + "' starting at " + to_string(LastLine) + " : " + Utilities::to_stringc(LastCharacter) + " is only numeric"); 411 | Utilities::Report(Name, Line, Character, msg); 412 | break; 413 | } 414 | else 415 | { 416 | ins.Name = Utilities::Hash(Keyword); 417 | Keyword.clear(); 418 | ins.Module = ActualModule; 419 | ins.Opcode = Opcodes::StartFunction; 420 | Database::PupilFInstructions.push_back(ins); 421 | IsFunction = false; 422 | FirstSpace = false; 423 | FirstChar = false; 424 | IsFunctionArguments = true; 425 | } 426 | } 427 | else if(Content[i] == ' ' || Content[i] == '\n') 428 | { 429 | if(Keyword.size() > 0) 430 | FirstSpace = true; 431 | } 432 | else if(FirstSpace) 433 | { 434 | const string c(1, Content[i]); 435 | const string msg("Expected '(', found '" + c + "'"); 436 | Utilities::Report(Name, Line, Character, msg); 437 | break; 438 | } 439 | else if(!Utilities::IsAlphanumeric(Content[i])) 440 | { 441 | const string c(1, Content[i]); 442 | const string msg("Invalid character '" + c + "'. Valid characters for a function name are '_', from '0' to '9', from 'A' to 'Z', and from 'a' to 'z'"); 443 | Utilities::Report(Name, Line, Character, msg); 444 | break; 445 | } 446 | else if(!FirstChar) 447 | { 448 | FirstChar = true; 449 | LastLine = Line; 450 | LastCharacter = Character; 451 | Keyword.push_back(Content[i]); 452 | } 453 | else 454 | Keyword.push_back(Content[i]); 455 | } 456 | else if(IsMain) 457 | { 458 | if(Content[i] != ' ' && Content[i] != '\n') 459 | { 460 | if(Content[i] == '{') 461 | { 462 | IsMain = false; 463 | MainFound = true; 464 | IsFunctionBody = true; 465 | MainFile = x; 466 | MainLine = LastLine; 467 | MainCharacter = LastCharacter; 468 | ins.Opcode = Opcodes::Main; 469 | Database::PupilFInstructions.push_back(ins); 470 | } 471 | else 472 | { 473 | const string msg("Expected '{'"); 474 | Utilities::Report(Name, Line, Character, msg); 475 | break; 476 | } 477 | } 478 | } 479 | else if(IsClass) 480 | { 481 | if(Content[i] == '{') 482 | { 483 | if(Utilities::nIsOnlyNumeric(Keyword.c_str(), Keyword.size())) 484 | { 485 | //error 486 | } 487 | else 488 | { 489 | IsClass = false; 490 | FirstChar = false; 491 | FirstSpace = false; 492 | ActualClass = Utilities::Hash(Keyword); 493 | Keyword.clear(); 494 | ins.Name = ActualClass; 495 | ins.Opcode = Opcodes::StartClass; 496 | Database::PupilFInstructions.push_back(ins); 497 | } 498 | } 499 | else if(Content[i] == ' ' || Content[i] == '\n') 500 | { 501 | if(Keyword.size() > 0) 502 | FirstSpace = true; 503 | } 504 | else if(FirstSpace) 505 | { 506 | //error 507 | } 508 | else if(!Utilities::IsAlphanumeric(Content[i])) 509 | { 510 | //error 511 | } 512 | else if(!FirstChar) 513 | { 514 | FirstChar = true; 515 | LastLine = Line; 516 | LastCharacter = Character; 517 | Keyword.push_back(Content[i]); 518 | } 519 | else 520 | Keyword.push_back(Content[i]); 521 | } 522 | else if(IsUsing) 523 | { 524 | if(Content[i] == ';') 525 | { 526 | if(Utilities::nIsOnlyNumeric(Keyword.c_str(), Keyword.size())) 527 | { 528 | const string msg("The using directive '" + Keyword + "' starting at " + to_string(LastLine) + " : " + Utilities::to_stringc(LastCharacter) + " is only numeric"); 529 | Utilities::Report(Name, Line, Character, msg); 530 | break; 531 | } 532 | else 533 | { 534 | IsUsing = false; 535 | FirstChar = false; 536 | FirstSpace = false; 537 | ins.Name = Utilities::Hash(Keyword); 538 | Keyword.clear(); 539 | ins.Opcode = Opcodes::Using; 540 | Database::PupilFInstructions.push_back(ins); 541 | } 542 | } 543 | else if(Content[i] == ' ' || Content[i] == '\n') 544 | { 545 | if(Keyword.size() > 0) 546 | FirstSpace = true; 547 | } 548 | else if(FirstSpace) 549 | { 550 | const string c(1, Content[i]); 551 | const string msg("Expected ';', but found '" + c + "'"); 552 | Utilities::Report(Name, Line, Character, msg); 553 | break; 554 | } 555 | else if(!Utilities::IsAlphanumeric(Content[i])) 556 | { 557 | const string c(1, Content[i]); 558 | const string msg("Invalid character '" + c + "', it's not alphanumeric. Valid characters are '_', from '0' to '9', from 'A' to 'Z', and from 'a' to 'z'"); 559 | Utilities::Report(Name, Line, Character, msg); 560 | break; 561 | } 562 | else if(!FirstChar) 563 | { 564 | FirstChar = true; 565 | LastLine = Line; 566 | LastCharacter = Character; 567 | Keyword.push_back(Content[i]); 568 | } 569 | else 570 | Keyword.push_back(Content[i]); 571 | } 572 | else if(IsSlowdown) 573 | { 574 | if(Content[i] == ' ' || Content[i] == '\n') 575 | { 576 | if(Keyword.size() > 0) 577 | { 578 | IsSlowdown = false; 579 | if(Database::UseVisualDebugger) 580 | { 581 | const size_t h = Utilities::Hash(Keyword); 582 | if(Utilities::IsOnlyNumeric(Keyword)) 583 | { 584 | stringstream ss(Keyword); 585 | Keyword.clear(); 586 | ss >> SleepTime; 587 | } 588 | else if(h == Hashes::Off) 589 | { 590 | Keyword.clear(); 591 | SleepTime = 0; 592 | } 593 | else 594 | { 595 | const string msg("The slowdown amount '" + Keyword + "' starting at " + to_string(LastLine) + " : " + to_string(LastCharacter) + ", is not only integer nor positive"); 596 | Utilities::Report(Name, Line, Character, msg); 597 | break; 598 | } 599 | } 600 | } 601 | else 602 | { 603 | const string msg("The time to slowdown is not specified"); 604 | Utilities::Report(Name, Line, Character, msg); 605 | break; 606 | } 607 | } 608 | else if(!FirstChar) 609 | { 610 | FirstChar = true; 611 | LastLine = Line; 612 | LastCharacter = Character; 613 | Keyword.push_back(Content[i]); 614 | } 615 | else 616 | Keyword.push_back(Content[i]); 617 | } 618 | else if(IsModule) 619 | { 620 | if(Content[i] == '{') 621 | { 622 | if(Utilities::nIsOnlyNumeric(Keyword.c_str(), Keyword.size())) 623 | { 624 | const string msg("The module name '" + Keyword + "' starting at " + to_string(LastLine) + " : " + Utilities::to_stringc(LastCharacter) + " is only numeric"); 625 | Utilities::Report(Name, Line, Character, msg); 626 | break; 627 | } 628 | else 629 | { 630 | if(ModuleCount > 0) 631 | Modules.append("."); 632 | ++ModuleCount; 633 | Modules.append(Keyword); 634 | Keyword.clear(); 635 | ActualModule = Utilities::Hash(Modules); 636 | ins.Name = ActualModule; 637 | ins.Opcode = Opcodes::StartModule; 638 | Database::PupilFInstructions.push_back(ins); 639 | IsModule = false; 640 | FirstChar = false; 641 | FirstSpace = false; 642 | } 643 | } 644 | else if(Content[i] == ' ' || Content[i] == '\n') 645 | { 646 | if(Keyword.size() > 0) 647 | FirstSpace = true; 648 | } 649 | else if(FirstSpace) 650 | { 651 | const string c(1, Content[i]); 652 | const string msg("Expected '{', found '" + c + "'"); 653 | Utilities::Report(Name, Line, Character, msg); 654 | break; 655 | } 656 | else if(!Utilities::IsAlphanumeric(Content[i])) 657 | { 658 | const string c(1, Content[i]); 659 | const string msg("Invalid character '" + c + "'. Valid characters for a module name are '_', from '0' to '9', from 'A' to 'Z', and from 'a' to 'z'"); 660 | Utilities::Report(Name, Line, Character, msg); 661 | break; 662 | } 663 | else if(!FirstChar) 664 | { 665 | FirstChar = true; 666 | LastLine = Line; 667 | LastCharacter = Character; 668 | Keyword.push_back(Content[i]); 669 | } 670 | else 671 | Keyword.push_back(Content[i]); 672 | } 673 | else if(Content[i] == ' ' || Content[i] == '\n') 674 | { 675 | if (Keyword.size() > 0) 676 | { 677 | FirstChar = false; 678 | if(IsMacro) 679 | { 680 | IsMacro = false; 681 | const size_t h = Utilities::Hash(Keyword); 682 | Keyword.clear(); 683 | if(h == Hashes::Sldown) 684 | IsSlowdown = true; 685 | } 686 | else 687 | { 688 | const size_t h = Utilities::Hash(Keyword); 689 | Keyword.clear(); 690 | if(h == Hashes::Module) 691 | IsModule = true; 692 | else if(h == Hashes::Function) 693 | IsFunction = true; 694 | else if(h == Hashes::Using) 695 | IsUsing = true; 696 | else if(h == Hashes::Class) 697 | IsClass = true; 698 | else if(h == Hashes::Main) 699 | { 700 | if(!MainFound) 701 | IsMain = true; 702 | else 703 | { 704 | const string msg("Main is already loaded at the file '" + Database::PupilFiles[MainFile] + "', " + to_string(MainLine) + " : " + Utilities::to_stringc(MainCharacter)); 705 | Utilities::Report(Name, Line, Character, msg); 706 | break; 707 | } 708 | } 709 | } 710 | } 711 | } 712 | else if(Content[i] == '#') 713 | IsMacro = true; 714 | else if(Content[i] == '}') 715 | { 716 | if(ModuleCount == 0) 717 | { 718 | const string msg("Invalid '}'"); 719 | Utilities::Report(Name, Line, Character, msg); 720 | break; 721 | } 722 | else if(Keyword.size() > 0) 723 | { 724 | const string msg("Invalid keyword '" + Keyword + "' starting at " + to_string(LastLine) + " : " + to_string(LastCharacter)); 725 | Utilities::Report(Name, Line, Character, msg); 726 | break; 727 | } 728 | else if(ModuleCount > 1) 729 | { 730 | --ModuleCount; 731 | ActualModule = Utilities::Hash(Modules); 732 | ins.Name = ActualModule; 733 | ins.Opcode = Opcodes::EndModule; 734 | Database::PupilFInstructions.push_back(ins); 735 | size_t xx = Modules.size() - 1; 736 | for(; xx > 0; --xx) 737 | if(Modules[xx] == '.') 738 | break; 739 | Modules.erase(xx, Modules.size() - xx); 740 | } 741 | else 742 | { 743 | ModuleCount = 0; 744 | ActualModule = Utilities::Hash(Modules); 745 | ins.Name = ActualModule; 746 | ins.Opcode = Opcodes::EndModule; 747 | Database::PupilFInstructions.push_back(ins); 748 | Modules.clear(); 749 | } 750 | } 751 | else if(!Utilities::IsAlphanumeric(Content[i])) 752 | { 753 | const string c(1, Content[i]); 754 | const string msg("Invalid character '" + c + "'. Valid characters are '_', from '0' to '9', from 'A' to 'Z', and from 'a' to 'z'"); 755 | Utilities::Report(Name, Line, Character, msg); 756 | break; 757 | } 758 | else if(!FirstChar) 759 | { 760 | FirstChar = true; 761 | LastLine = Line; 762 | LastCharacter = Character; 763 | Keyword.push_back(Content[i]); 764 | } 765 | else 766 | Keyword.push_back(Content[i]); 767 | } 768 | if(Keyword.size() > 0) 769 | { 770 | if(IsModule) 771 | { 772 | const string msg("Expected '{' after the module name '" + Keyword + "' starting at " + to_string(LastLine) + " : " + Utilities::to_stringc(LastCharacter)); 773 | Utilities::Report(Name, Line, Character, msg); 774 | } 775 | else 776 | { 777 | const string msg("Invalid keyword '" + Keyword + "' starting at " + to_string(LastLine) + " : " + Utilities::to_stringc(LastCharacter) + " is invalid"); 778 | Utilities::Report(Name, Line, Character, msg); 779 | } 780 | } 781 | else if(ModuleCount > 0) 782 | { 783 | const string msg("Expected '}'"); 784 | Utilities::Report(Name, Line, Character, msg); 785 | } 786 | else if(IsModule) 787 | { 788 | const string msg("Expected the module name after the 'module' specifier starting at " + to_string(LastLine) + " : " + Utilities::to_stringc(LastCharacter)); 789 | Utilities::Report(Name, Line, Character, msg); 790 | } 791 | const chrono::steady_clock::time_point b = Utilities::TimePoint(); 792 | const string s = Utilities::TimeDiff(a, b); 793 | Console::Append("\n\nReading and parsing the iris file '" + Name + "' took " + s); 794 | } 795 | } 796 | } 797 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Project-Iris 2 | Iris systems programming language frontend & backend(yes, it's a one-man project) 3 | -------------------------------------------------------------------------------- /Structures.hpp: -------------------------------------------------------------------------------- 1 | //Copyright 2020 Iris Technologies, All Rights Reserved 2 | #pragma once 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | 8 | namespace ProjectIris 9 | { 10 | namespace Hashes 11 | { 12 | constexpr size_t InitApp = 4229616916362953318;//initapp 13 | 14 | constexpr size_t IsConsole = 4280226163429640506;//isconsole 15 | 16 | constexpr size_t Natlib = 2283687954489727723;//natlib 17 | 18 | constexpr size_t Ignore = 12181781538219395523;//ignore 19 | 20 | constexpr size_t UseVisualDebugger = 4970868739992279183;//usevisualdebugger 21 | 22 | constexpr size_t MeasureType = 9985186892661743463;//measuretype 23 | 24 | constexpr size_t ReportPupil = 15381437785649700129;//reportpupil 25 | 26 | constexpr size_t Name = 14176396743819860870;//name 27 | 28 | constexpr size_t Type = 12075340201627130925;//type 29 | 30 | constexpr size_t Executable = 13678059843563106925;//executable 31 | 32 | constexpr size_t Library = 16152639334691645584;//library 33 | 34 | constexpr size_t Sandbox = 3331646911590050372;//sandbox 35 | 36 | constexpr size_t Nanoseconds = 626911876451167078;//ns 37 | 38 | constexpr size_t Microseconds = 582730275372608502;//mcs 39 | 40 | constexpr size_t Milliseconds = 624114718869565969;//ms 41 | 42 | constexpr size_t Off = 1883801076392705514;//off 43 | 44 | constexpr size_t Sldown = 5780042772118102530;//sldown 45 | 46 | constexpr size_t Stop = 12618894948741332165;//stop 47 | 48 | constexpr size_t Module = 4892776386767805149;//module 49 | 50 | constexpr size_t Using = 15689622396028117031;//using 51 | 52 | constexpr size_t Function = 619343937915704565;//fn 53 | 54 | constexpr size_t Main = 2258945139493307336;//main 55 | 56 | constexpr size_t In = 628032278800124862;//in 57 | 58 | constexpr size_t Out = 1871134702438174719;//out 59 | 60 | constexpr size_t Inout = 4023996569761782818;//inout 61 | 62 | constexpr size_t Const = 7334518323283222324;//const 63 | 64 | constexpr size_t Class = 15066323702654938015;//class 65 | 66 | constexpr size_t OperatorPlus = 5084307088801188994;//operator+ 67 | 68 | constexpr size_t OperatorMinus = 5084300491731419728;//operator- 69 | 70 | constexpr size_t OperatorEqual = 5084282899545368352;//operator= 71 | 72 | constexpr size_t OperatorMultiplication = 5084308188312817205;//operator* 73 | 74 | constexpr size_t OperatorDivision = 5084302690754676150;//operator/ 75 | 76 | constexpr size_t OperatorIncrement = 16424530381718799147;//operator++ 77 | 78 | constexpr size_t OperatorDecrement = 16418797528090442343;//operator-- 79 | 80 | constexpr size_t OperatorPlusEqual = 16424554570974619789;//operator+= 81 | 82 | constexpr size_t OperatorMinusEqual = 16418779935904390967;//operator-= 83 | 84 | constexpr size_t OperatorMultiplicationEqual = 16425394597858383768; //operator*= 85 | 86 | constexpr size_t OperatorDivisionEqual = 16420613921299868465;//operator/= 87 | 88 | constexpr size_t Equal = 12638138822044000712;//= 89 | 90 | constexpr size_t S8 = 637547452428770606;//s8 91 | } 92 | 93 | namespace Opcodes 94 | { 95 | constexpr unsigned short Nothing = 0; 96 | 97 | constexpr unsigned short NewFile = 1; 98 | 99 | constexpr unsigned short StartModule = 2; 100 | 101 | constexpr unsigned short EndModule = 3; 102 | 103 | constexpr unsigned short Using = 4; 104 | 105 | constexpr unsigned short StartFunction = 5; 106 | 107 | constexpr unsigned short EndFunction = 6; 108 | 109 | constexpr unsigned short InArgument = 7; 110 | 111 | constexpr unsigned short InoutArgument = 8; 112 | 113 | constexpr unsigned short OutArgument = 9; 114 | 115 | constexpr unsigned short ArgumentType = 10; 116 | 117 | constexpr unsigned short ArgumentName = 11; 118 | 119 | constexpr unsigned short FunctionBody = 12; 120 | 121 | constexpr unsigned short LvalueKeyword = 13; 122 | 123 | constexpr unsigned short EqualOperation = 14; 124 | 125 | constexpr unsigned short RvalueKeyword = 15; 126 | 127 | constexpr unsigned short LocalVariableType = 16; 128 | 129 | constexpr unsigned short LocalVariableName = 17; 130 | 131 | constexpr unsigned short StartClass = 18; 132 | 133 | constexpr unsigned short Main = 19; 134 | } 135 | 136 | struct Bytes8 137 | { 138 | unsigned char a, b, c, d, e, f, g, h; 139 | }; 140 | 141 | struct Bytes4 142 | { 143 | unsigned char a, b, c, d; 144 | }; 145 | 146 | struct Bytes2 147 | { 148 | unsigned char a, b; 149 | }; 150 | 151 | struct PESection 152 | { 153 | unsigned int PointerToRawData, VirtualEnd, VirtualAddress;//VirtualEnd = VirtualAddress + VirtualSize 154 | }; 155 | 156 | struct PENativeSection 157 | { 158 | unsigned int PointerToRawData, SizeOfRawData, VirtualAddress, VirtualSize; 159 | }; 160 | 161 | enum class OperatingSystem : unsigned char 162 | { 163 | Windows, 164 | Xbox, 165 | 166 | }; 167 | 168 | struct ErrorPoint 169 | { 170 | size_t Line, Character; 171 | 172 | string File, Message; 173 | 174 | __forceinline void clear() noexcept 175 | { 176 | File.clear(); 177 | Message.clear(); 178 | } 179 | }; 180 | 181 | struct NativeLibrary 182 | { 183 | size_t Line, Character; 184 | 185 | string Name; 186 | }; 187 | 188 | enum class MeasureTypes : unsigned char 189 | { 190 | Nanoseconds, 191 | Microseconds, 192 | Milliseconds 193 | }; 194 | 195 | enum class ProjectType : unsigned char 196 | { 197 | Sandbox, 198 | Library, 199 | Executable 200 | }; 201 | 202 | struct IgnoredFile 203 | { 204 | size_t Line, Character; 205 | 206 | string Name; 207 | }; 208 | 209 | enum class ArgumentDirection : unsigned char 210 | { 211 | In, 212 | Out, 213 | Inout 214 | }; 215 | 216 | struct Argument 217 | { 218 | size_t Type; 219 | 220 | ArgumentDirection Direction; 221 | }; 222 | 223 | struct FunctionPrototype 224 | { 225 | size_t Name, Character, Line; 226 | 227 | vector Arguments; 228 | }; 229 | 230 | struct PupilFInstruction 231 | { 232 | bool IsLiteral = false; 233 | 234 | unsigned short Opcode; 235 | 236 | size_t Pointer, Module, Name, Line, Character; 237 | }; 238 | 239 | struct RegisterAliasing 240 | { 241 | size_t VarName; 242 | 243 | char Register; 244 | }; 245 | } -------------------------------------------------------------------------------- /Utilities.hpp: -------------------------------------------------------------------------------- 1 | //Copyright 2020 Iris Technologies, All Rights Reserved 2 | #pragma once 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | using namespace std; 16 | 17 | namespace ProjectIris 18 | { 19 | namespace Utilities 20 | { 21 | __forceinline vector GetFilesInFolder(const string& Path, const bool IsRetina = false) noexcept 22 | { 23 | vector v; 24 | for (const auto& File : filesystem::recursive_directory_iterator(Path)) 25 | { 26 | string f = File.path().string(); 27 | if(f.size() > static_cast(6)) 28 | { 29 | if(!IsRetina) 30 | { 31 | if (f[f.size() - 1] == 's' && f[f.size() - 2] == 'i' && f[f.size() - 3] == 'r' && f[f.size() - 4] == 'i' && f[f.size() - 5] == '.') 32 | { 33 | bool Exists = false; 34 | for(size_t x = 0; x < Database::IgnoredIris.size(); ++x) 35 | if(Database::IgnoredIris[x] == f) 36 | { 37 | Exists = true; 38 | Database::ConsoleBuffer.append("\n\nIgnored iris file '" + f + "'"); 39 | break; 40 | } 41 | if(!Exists) 42 | v.push_back(f); 43 | } 44 | } 45 | else if(f[f.size() - 1] == 'a' && f[f.size() - 2] == 'n' && f[f.size() - 3] == 'i' && f[f.size() - 4] == 't' && f[f.size() - 5] == 'e' && f[f.size() - 6] == 'r' && f[f.size() - 7] == '.') 46 | { 47 | bool Exists = false; 48 | for(size_t x = 0; x < Database::IgnoredRetina.size(); ++x) 49 | if(Database::IgnoredRetina[x] == f) 50 | { 51 | Exists = true; 52 | Database::ConsoleBuffer.append("\n\nIgnored retina file '" + f + "'"); 53 | break; 54 | } 55 | if(!Exists) 56 | v.push_back(f); 57 | } 58 | } 59 | } 60 | return v; 61 | } 62 | 63 | __forceinline void InitApp(const string& path) noexcept 64 | { 65 | STARTUPINFOA info={sizeof(info)}; 66 | PROCESS_INFORMATION processInfo; 67 | if (CreateProcessA(path.c_str(), Database::Commands.data(), 0, 0, 1, 0, 0, 0, &info, &processInfo)) 68 | { 69 | WaitForSingleObject(processInfo.hProcess, INFINITE); 70 | CloseHandle(processInfo.hProcess); 71 | CloseHandle(processInfo.hThread); 72 | } 73 | } 74 | 75 | __forceinline size_t Hash(const string& s) noexcept 76 | { 77 | return hash()(s); 78 | } 79 | 80 | __forceinline bool FileExists(const string& Path) noexcept 81 | { 82 | DWORD dwAttrib = GetFileAttributesA(Path.c_str()); 83 | return (dwAttrib != INVALID_FILE_ATTRIBUTES && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); 84 | } 85 | 86 | __forceinline bool DirectoryExists(const string& Path) noexcept 87 | { 88 | DWORD dwAttrib = GetFileAttributesA(Path.c_str()); 89 | return (dwAttrib != INVALID_FILE_ATTRIBUTES && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); 90 | } 91 | 92 | __forceinline string ReadFile(const string& Path) noexcept 93 | { 94 | string s; 95 | OVERLAPPED o = {0}; 96 | LARGE_INTEGER size; 97 | HANDLE h = CreateFileA(Path.c_str(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, 0); 98 | if(h != INVALID_HANDLE_VALUE) 99 | { 100 | GetFileSizeEx(h, &size); 101 | s.resize(size.LowPart); 102 | ReadFileEx(h, &s[0], size.LowPart, &o, 0); 103 | CloseHandle(h); 104 | } 105 | s.erase(remove(s.begin(), s.end(), '\t'), s.end()); 106 | s.erase(remove(s.begin(), s.end(), '\r'), s.end()); 107 | return s; 108 | } 109 | 110 | __forceinline void WriteFile(const string& Path, const string& Content) noexcept 111 | { 112 | if(FileExists(Path)) 113 | DeleteFileA(Path.c_str()); 114 | HANDLE h = CreateFileA(Path.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, 0, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0); 115 | if(h != INVALID_HANDLE_VALUE) 116 | { 117 | OVERLAPPED o = {0}; 118 | WriteFileEx(h, &Content[0], Content.size(), &o, 0); 119 | CloseHandle(h); 120 | } 121 | } 122 | 123 | __forceinline void CreateDirectory(const string& Path) noexcept 124 | { 125 | filesystem::create_directories(Path); 126 | } 127 | 128 | __forceinline vector ReadBinary(const string& Path) noexcept 129 | { 130 | vector s; 131 | OVERLAPPED o = {0}; 132 | LARGE_INTEGER size; 133 | HANDLE h = CreateFileA(Path.c_str(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, 0); 134 | if(h != INVALID_HANDLE_VALUE) 135 | { 136 | GetFileSizeEx(h, &size); 137 | s.resize(size.LowPart); 138 | ReadFileEx(h, &s[0], size.LowPart, &o, 0); 139 | CloseHandle(h); 140 | } 141 | return s; 142 | } 143 | 144 | __forceinline void WriteBinary(const string& Path, const vector& Content) noexcept 145 | { 146 | if(FileExists(Path)) 147 | DeleteFileA(Path.c_str()); 148 | HANDLE h = CreateFileA(Path.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, 0, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0); 149 | if(h != INVALID_HANDLE_VALUE) 150 | { 151 | OVERLAPPED o = {0}; 152 | WriteFileEx(h, &Content[0], Content.size(), &o, 0); 153 | CloseHandle(h); 154 | } 155 | } 156 | 157 | __forceinline string GetDirectory(const string& Path) noexcept 158 | { 159 | return Path.substr(0, Path.find_last_of("\\/")); 160 | } 161 | 162 | __forceinline bool IsOnlyNumeric(const string& s) noexcept 163 | { 164 | for(size_t x = 0; x < s.size(); ++x) 165 | if(s[x] < '0' || s[x] > '9') 166 | return false; 167 | return true; 168 | } 169 | 170 | __forceinline bool nIsOnlyNumeric(const char* s, const size_t s_size) noexcept 171 | { 172 | for(size_t x = 0; x < s_size; ++x) 173 | if(s[x] < '0' || s[x] > '9') 174 | return false; 175 | return true; 176 | } 177 | 178 | __forceinline bool IsAlphanumeric(const char c) noexcept 179 | { 180 | return (c == '_' || (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')); 181 | } 182 | 183 | __forceinline string to_stringc(size_t Character) noexcept 184 | { 185 | if(Character == 0) 186 | Character = 1; 187 | return to_string(Character); 188 | } 189 | 190 | __forceinline void Report(const string& File, const size_t Line, size_t Character, const string& Message) noexcept 191 | { 192 | if(Character == 0) 193 | Character = 1; 194 | Database::PupilError = true; 195 | if(Database::UseVisualDebugger) 196 | { 197 | Database::Report.File = File; 198 | Database::Report.Line = Line; 199 | Database::Report.Character = Character; 200 | Database::Report.Message = Message; 201 | } 202 | else 203 | { 204 | const string m = "\n\nError at the file '" + File + "', " + to_string(Line) + " : " + to_string(Character) + " -> " + Message; 205 | Database::ConsoleBuffer.append(m); 206 | } 207 | } 208 | 209 | __forceinline void Cleanup() noexcept 210 | { 211 | if(Database::os == OperatingSystem::Windows || Database::os == OperatingSystem::Xbox) 212 | Database::Binary.resize(552); 213 | Database::InitApp = false; 214 | Database::LastMessage = false; 215 | Database::IsConsole = false; 216 | Database::LinkerError = false; 217 | Database::PupilError = false; 218 | Database::UseVisualDebugger = false; 219 | Database::ReportPupil = false; 220 | Database::mtp = MeasureTypes::Microseconds; 221 | Database::os = OperatingSystem::Windows; 222 | Database::pt = ProjectType::Sandbox; 223 | Database::MajorWindowsVersion = 5; 224 | Database::MinorWindowsVersion = 2; 225 | Database::MajorAppVersion = 0; 226 | Database::MinorAppVersion = 0; 227 | Database::ActualLine = 0; 228 | Database::ActualCharacter = 0; 229 | Database::Report.clear(); 230 | Database::ActualFile.clear(); 231 | Database::PupilFiles.clear(); 232 | Database::IgnoredIris.clear(); 233 | Database::ConsoleBuffer.clear(); 234 | Database::ExportedSymbols.clear(); 235 | Database::IrisFiles.clear(); 236 | Database::NativeSections.clear(); 237 | Database::NativeLibraries.clear(); 238 | Database::ProjectName.clear(); 239 | Database::PupilFInstructions.clear(); 240 | Database::Text.clear(); 241 | Database::Commands.clear(); 242 | } 243 | 244 | __forceinline void Recompile() noexcept 245 | { 246 | const string h(Database::ConsoleBuffer + "\n\n\nPress 'r' to execute again or any other key to exit..."); 247 | cout << h << endl; 248 | if(Database::InitApp) 249 | InitApp(Database::OutputFolder + Database::ProjectName + ".exe"); 250 | char c; 251 | cin >> c; 252 | if (c == 'r') 253 | { 254 | Cleanup(); 255 | Execute(); 256 | } 257 | } 258 | 259 | __forceinline chrono::steady_clock::time_point TimePoint() noexcept 260 | { 261 | return chrono::steady_clock::now(); 262 | } 263 | 264 | __forceinline string TimeDiff(const chrono::steady_clock::time_point& begin, const chrono::steady_clock::time_point& end) noexcept 265 | { 266 | if(Database::mtp == MeasureTypes::Nanoseconds) 267 | return to_string(chrono::duration_cast(end - begin).count()) + " nanoseconds"; 268 | else if(Database::mtp == MeasureTypes::Microseconds) 269 | return to_string(chrono::duration_cast(end - begin).count()) + " microseconds"; 270 | return to_string(chrono::duration_cast(end - begin).count()) + " milliseconds"; 271 | } 272 | 273 | __forceinline double TimeDiffD(const chrono::steady_clock::time_point& begin, const chrono::steady_clock::time_point& end) noexcept 274 | { 275 | return chrono::duration_cast(end - begin).count(); 276 | } 277 | 278 | __forceinline unsigned int BytesToUint(const unsigned char a, const unsigned char b, const unsigned char c, const unsigned char d) noexcept 279 | { 280 | return ((d << 24) | (c << 16) | (b << 8) | a); 281 | } 282 | 283 | __forceinline Bytes4 UintToBytes(const unsigned int u) noexcept 284 | { 285 | return {static_cast((u & 0xff000000) >> 24), static_cast((u & 0x00ff0000) >> 16), static_cast((u & 0x0000ff00) >> 8), static_cast(u & 0x000000ff)}; 286 | } 287 | 288 | __forceinline unsigned short BytesToUshort(const unsigned char a, const unsigned char b) noexcept 289 | { 290 | return ((b << 8) | a); 291 | } 292 | 293 | __forceinline Bytes2 UshortToBytes(const unsigned short u) noexcept 294 | { 295 | return {static_cast((u & 0xff00) >> 8), static_cast(u & 0x00ff)}; 296 | } 297 | 298 | __forceinline Bytes8 UlongToBytes(const unsigned long long u) noexcept 299 | { 300 | return {static_cast((u & 0xff00000000000000) >> 56), static_cast((u &0x00ff000000000000) >> 48), static_cast((u & 0x0000ff0000000000) >> 40), static_cast((u & 0x000000ff00000000) >> 32), static_cast((u & 0x00000000ff000000) >> 24), static_cast((u & 0x0000000000ff0000) >> 16), static_cast((u & 0x000000000000ff00) >> 8), static_cast(u & 0x00000000000000ff)}; 301 | } 302 | } 303 | } -------------------------------------------------------------------------------- /VisualDebugger.hpp: -------------------------------------------------------------------------------- 1 | //Copyright 2020 Iris Technologies, All Rights Reserved 2 | #pragma once 3 | #include 4 | #include 5 | 6 | namespace ProjectIris 7 | { 8 | namespace VisualDebugger 9 | { 10 | __forceinline void Start() noexcept 11 | { 12 | //Soon it will have more astonishing uses, just wait and see :D 13 | sf::RenderWindow Window(sf::VideoMode(1200, 600), "Project Iris - Visual Debugger"); 14 | sf::Font font; 15 | if(font.loadFromFile("C:\\ProjectIris\\Crimson-Bold.ttf")) 16 | { 17 | sf::Text text; 18 | text.setFont(font); 19 | text.setCharacterSize(28); 20 | sf::Text text2; 21 | text2.setFont(font); 22 | text2.setCharacterSize(28); 23 | text2.setPosition(0, 50); 24 | while(Window.isOpen()) 25 | { 26 | sf::Event Event; 27 | while(Window.pollEvent(Event)) 28 | if(Event.type == sf::Event::Closed) 29 | Window.close(); 30 | Window.clear(); 31 | text.setString("File: " + Database::ActualFile + ", Line: " + to_string(Database::ActualLine) + ", Character: " + to_string(Database::ActualCharacter)); 32 | if(Database::Report.Message.size() > 0) 33 | text2.setString("Error report at '" + Database::Report.File + "', " + to_string(Database::Report.Line) + " : " + to_string(Database::Report.Character) + " -> " + Database::Report.Message); 34 | Window.draw(text); 35 | Window.draw(text2); 36 | Window.display(); 37 | } 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /X64.hpp: -------------------------------------------------------------------------------- 1 | //Copyright 2020 Iris Technologies, All Rights Reserved 2 | #pragma once 3 | 4 | namespace ProjectIris 5 | { 6 | namespace X64 7 | { 8 | constexpr unsigned char Mov8ImmToAl = 0xb0; 9 | 10 | 11 | } 12 | } --------------------------------------------------------------------------------