From 9ef907736875a016e463503caccf4ee6c1de97d4 Mon Sep 17 00:00:00 2001 From: xolatile Date: Sun, 8 Jun 2025 21:56:29 +0000 Subject: [PATCH] Test... --- xanguage.h | 231 +++++++++++++++++++++++++ xatrix.h | 495 +++++++++++++++++++++++++++++++++++++++++++++++++++++ xector.h | 438 +++++++++++++++++++++++++++++++++++++++++++++++ xrena.h | 164 ++++++++++++++++++ xyntax.h | 238 ++++++++++++++++++++++++++ 5 files changed, 1566 insertions(+) create mode 100644 xanguage.h create mode 100644 xatrix.h create mode 100644 xector.h create mode 100644 xrena.h create mode 100644 xyntax.h diff --git a/xanguage.h b/xanguage.h new file mode 100644 index 0000000..723e6c1 --- /dev/null +++ b/xanguage.h @@ -0,0 +1,231 @@ +/// __ ____ _ _ __ __ _ _ _ __ _ __ _ ___ +/// \ \/ / _` | '_ \ / _` | | | |/ _` |/ _` |/ _ \ +/// > < (_| | | | | (_| | |_| | (_| | (_| | __/ +/// /_/\_\__,_|_| |_|\__, |\__,_|\__,_|\__, |\___| +/// |___/ |___/ +/// +/// Copyright (c) 1997 - Ognjen 'xolatile' Milan Robovic +/// +/// xolatile@chud.cyou - xanguage - Syntax definitions of programming languages that I care about (and some that I don't care about). +/// +/// This program is free software, free as in freedom and as in free beer, you can redistribute it and/or modify it under the terms of the GNU +/// General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version if you wish... +/// +/// This program is distributed in the hope that it will be useful, but it is probably not, and without any warranty, without even the implied +/// warranty of merchantability or fitness for a particular purpose, because it is pointless. Please see the GNU (Geenoo) General Public License +/// for more details, if you dare, it is a lot of text that nobody wants to read... + +/// Description +/// +/// Xanguage, core programming and scripting language definitions created using Xyntax, with few more output definitions that I care about, for +/// example Valgrind. There's not much to document about this library, it's used in my projects Xarbon and Xighlight. You can add support for +/// your language of choice by adding one enumeration value, creating header file similar to existing ones, including it here and editing +/// functions below to match 'language_count'. If you don't like how I highlight one or more of these languages, feel free to add more fields in +/// 'language_structure' or edit existing ones inside 'xanguage' folder. This header file may look unfamiliar, especially to my other projects, +/// but that's the cost of highlighting multiple languages in very low amount of code. + +/// Enumeration of supported languages, in no particular order. + +typedef enum { + language_common, language_ada, language_c, language_cpp, + language_d, language_eaxhla, language_flat, language_fortran, + language_pascal, language_python, language_go, language_lua, + language_bash, language_haskell, language_valgrind, language_holy_c, + language_count +} language_enumeration; + +/// Structure of single language definition, highlighting-wise, this will be initialized below, check out how it is used. +/// +/// language_structure * language = null; + +typedef struct { + natural comment_colour; /// Colours for basic language syntax information. + natural processor_colour; + natural character_colour; + natural string_colour; + natural keyword_colour; + natural type_colour; + natural bracket_colour; + natural operator_colour; + natural number_colour; + natural lowercase_colour; + natural uppercase_colour; + natural underscore_colour; + natural register_colour; + natural extension_colour; + natural fatal_colour; + natural comment_effect; /// Effects for basic language syntax information. + natural processor_effect; + natural character_effect; + natural string_effect; + natural keyword_effect; + natural type_effect; + natural bracket_effect; + natural operator_effect; + natural number_effect; + natural lowercase_effect; + natural uppercase_effect; + natural underscore_effect; + natural register_effect; + natural extension_effect; + natural fatal_effect; +} language_structure; + +/// Warning: Local macros! You don't need to use this at all, it's covered by other functions, don't worry about it. +/// +/// You shouldn't care about these local macros, they made few lines of code shorter, we're including files in this order, in this place. + +#define language_lowercase "abcdefghijklmnopqrstuvwxyz" +#define language_uppercase "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +#define language_letters "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" +#define language_digits "0123456789" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef language_lowercase +#undef language_uppercase +#undef language_letters +#undef language_digits + +/// Array of function pointers enumerated above, these functions are defined in separate header files in 'xanguage' folder. + +static procedure (* language_highlighter [language_count]) (language_structure * language, syntax_structure * syntax) = { + language_highlight_common, language_highlight_ada, language_highlight_c, language_highlight_cpp, + language_highlight_d, language_highlight_eaxhla, language_highlight_flat, language_highlight_fortran, + language_highlight_pascal, language_highlight_python, language_highlight_go, language_highlight_lua, + language_highlight_bash, language_highlight_haskell, language_highlight_valgrind, language_highlight_holy_c +}; + +/// Array of short command line argument enumerated above, makes main function less bloated. + +static character * language_short_option [language_count] = { + "-X", "-A", "-C", "-S", "-D", "-E", "-T", "-F", "-P", "-Y", "-G", "-L", "-B", "-H", "-V", "-O" +}; + +/// Array of long command line argument enumerated above, makes main function less bloated. + +static character * language_long_option [language_count] = { + "--common", "--ada", "--c", "--cpp", "--d", "--eaxhla", "--flat", "--fortran", + "--pascal", "--python", "--go", "--lua", "--bash", "--haskell", "--valgrind", "--holyc" +}; + +/// Array of pretty language name enumerated above, makes things pretty. + +static character * language_identifier [language_count] = { + "Common", "Ada", "C", "C++", "D", "EAXHLA", "Flat", "Fortran", + "Pascal", "Python", "Go", "Lua", "Bash", "Haskell", "Valgrind", "Holy C" +}; + +/// After you've defined global or local language variable, you want to initialize it, edit this function if you dislike my themes. +/// +/// language = language_initialize (false); /// You're probably using this library to render an image. +/// language = language_initialize (true); /// You're probably using this library to print to terminal. + +static language_structure * language_initialize (boolean true_colour) { + language_structure * language = allocate (sizeof (* language)); + + if (true_colour == true) { + language->comment_colour = 0xff777777u; + language->processor_colour = 0xff3377aau; + language->character_colour = 0xff7733ccu; + language->string_colour = 0xffcc3377u; + language->keyword_colour = 0xff33cceeu; + language->type_colour = 0xff55cceeu; + language->bracket_colour = 0xffee5533u; + language->operator_colour = 0xffeeaa33u; + language->number_colour = 0xffee33aau; + language->lowercase_colour = 0xffccccccu; + language->uppercase_colour = 0xffeeeeeeu; + language->underscore_colour = 0xffaaaaaau; + language->register_colour = 0xff5577aau; + language->extension_colour = 0xff55aaccu; + language->fatal_colour = 0xffcc7755u; + } else { + language->comment_colour = colour_grey; + language->processor_colour = colour_cyan; + language->character_colour = colour_pink; + language->string_colour = colour_pink; + language->keyword_colour = colour_yellow; + language->type_colour = colour_yellow; + language->bracket_colour = colour_blue; + language->operator_colour = colour_cyan; + language->number_colour = colour_pink; + language->lowercase_colour = colour_white; + language->uppercase_colour = colour_white; + language->underscore_colour = colour_white; + language->register_colour = colour_cyan; + language->extension_colour = colour_yellow; + language->fatal_colour = colour_red; + language->comment_effect = effect_bold; + language->processor_effect = effect_italic; + language->character_effect = effect_bold; + language->string_effect = effect_normal; + language->keyword_effect = effect_bold; + language->type_effect = effect_normal; + language->bracket_effect = effect_bold; + language->operator_effect = effect_normal; + language->number_effect = effect_bold; + language->lowercase_effect = effect_normal; + language->uppercase_effect = effect_bold; + language->underscore_effect = effect_italic; + language->register_effect = effect_italic; + language->extension_effect = effect_italic; + language->fatal_effect = effect_bold; + } + + return (language); +} + +/// When you're done doing your thing, just call this function nicely to avoid leaking memory. +/// +/// language = language_deinitialize (language); + +static language_structure * language_deinitialize (language_structure * language) { + return (deallocate (language)); +} + +/// This is just a helper function that I used a lot, it made sense to define it in this file, so here it is... This function will call specific +/// function from 'xanguage' folder, based on what file type you pass to it, enumerated in Xtandard. It takes natural number as selection value +/// due to avoiding type-related errors that dumb compilers might warn about, because some C compilers treat enumeration values as signed, while +/// others treat them as unsigned, unless you manually define some value there negative, which is braindead. +/// +/// language_conditionally_select (language, syntax, selection_index); + +static procedure language_conditionally_select (language_structure * language, syntax_structure * syntax, natural select) { + if (syntax->count == 0) { + if ((select == file_type_c_source) || (select == file_type_c_header)) { + language_highlight_c (language, syntax); + } else if ((select == file_type_ada_sexy_body) || (select == file_type_ada_specification)) { + language_highlight_ada (language, syntax); + } else if ((select == file_type_cpp_source) || (select == file_type_cpp_header)) { + language_highlight_cpp (language, syntax); + } else if (select == file_type_flat_assembly) { + language_highlight_flat (language, syntax); + } else if (select == file_type_fortran_90_source) { + language_highlight_fortran (language, syntax); + } else if (select == file_type_pascal_source) { + language_highlight_pascal (language, syntax); + } else if (select == file_type_eax_assembly) { + language_highlight_eaxhla (language, syntax); + } else if (select == file_type_python_script) { + language_highlight_python (language, syntax); + } else { + language_highlight_common (language, syntax); + } + } +} diff --git a/xatrix.h b/xatrix.h new file mode 100644 index 0000000..7d497af --- /dev/null +++ b/xatrix.h @@ -0,0 +1,495 @@ +/// _ _ +/// __ ____ _| |_ _ __(_)_ __ +/// \ \/ / _` | __| '__| \ \/ / +/// > < (_| | |_| | | |> < +/// /_/\_\__,_|\__|_| |_/_/\_\ +/// +/// Copyright (c) 1997 - Ognjen 'xolatile' Milan Robovic +/// +/// xolatile@chud.cyou - xatrix - Very dumb and slow matrix library, mathematical matrix, because I don't like other people ideas... +/// +/// This program is free software, free as in freedom and as in free beer, you can redistribute it and/or modify it under the terms of the GNU +/// General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version if you wish... +/// +/// This program is distributed in the hope that it will be useful, but it is probably not, and without any warranty, without even the implied +/// warranty of merchantability or fitness for a particular purpose, because it is pointless. Please see the GNU (Geenoo) General Public License +/// for more details, if you dare, it is a lot of text that nobody wants to read... + +/// Description +/// +/// Xatrix, my tiny braindead unoptimized matrix library. Unlike vectors that use x, y, z and w structure fields, matrices are double array of +/// 32-bit floating point numbers, and they're accessed with integers, which should've been the same case with vectors, but mathematicians are +/// dumb sometimes (blame it on the one being older than the other one?). Again, nothing much to talk about here, learn linear algebra, include +/// this header file in your project, use it however you want, compilers might optimize this better than my vector library. This library isn't +/// intended for neural networks, as it's not generic, it can be used in simple CPU-based ray tracers and physics simulations. + +/// Nice 2D, 3D and 4D matrix structures. + +typedef real matrix_2 [2] [2]; /// Tiny 2x2 matrix. +typedef real matrix_3 [3] [3]; /// Tiny 3x3 matrix. +typedef real matrix_4 [4] [4]; /// Tiny 4x4 matrix. + +/// Assign values to 2D, 3D or 4D matrix and return address of that matrix. + +static matrix_2 * matrix_2_assign (matrix_2 * destination, + real m00, real m01, + real m10, real m11) { + destination [0] [0] = m00; destination [0] [1] = m01; + destination [1] [0] = m10; destination [1] [1] = m11; + + return (destination); +} + +static matrix_3 * matrix_3_assign (matrix_3 * destination, + real m00, real m01, real m02, + real m10, real m11, real m12, + real m20, real m21, real m22) { + destination [0] [0] = m00; destination [0] [1] = m01; destination [0] [2] = m02; + destination [1] [0] = m10; destination [1] [1] = m11; destination [1] [2] = m12; + destination [2] [0] = m20; destination [2] [1] = m21; destination [2] [2] = m22; + + return (destination); +} + +static matrix_4 * matrix_4_assign (matrix_4 * destination, + real m00, real m01, real m02, real m03, + real m10, real m11, real m12, real m13, + real m20, real m21, real m22, real m23, + real m30, real m31, real m32, real m33) { + destination [0] [0] = m00; destination [0] [1] = m01; destination [0] [2] = m02; destination [0] [3] = m03; + destination [1] [0] = m10; destination [1] [1] = m11; destination [1] [2] = m12; destination [1] [3] = m13; + destination [2] [0] = m20; destination [2] [1] = m21; destination [2] [2] = m22; destination [2] [3] = m23; + destination [3] [0] = m30; destination [3] [1] = m31; destination [3] [2] = m32; destination [3] [3] = m33; + + return (destination); +} + +/// Nullify values of 2D, 3D or 4D matrix and return address of that matrix. + +static matrix_2 * matrix_2_nullify (matrix_2 * destination) { + for (natural row = 0; row < 2; ++row) { + for (natural column = 0; column < 2; ++column) { + destination [row] [column] = 0.0f; + } + } + + return (destination); +} + +static matrix_3 * matrix_3_nullify (matrix_3 * destination) { + for (natural row = 0; row < 3; ++row) { + for (natural column = 0; column < 3; ++column) { + destination [row] [column] = 0.0f; + } + } + + return (destination); +} + +static matrix_4 * matrix_4_nullify (matrix_4 * destination) { + for (natural row = 0; row < 4; ++row) { + for (natural column = 0; column < 4; ++column) { + destination [row] [column] = 0.0f; + } + } + + return (destination); +} + +/// Identify values of 2D, 3D or 4D matrix and return address of that matrix. + +static matrix_2 * matrix_2_identity (matrix_2 * destination) { + destination = matrix_2_nullify (destination); + + for (natural index = 0; index < 2; ++index) { + destination [index] [index] = 1.0f; + } + + return (destination); +} + +static matrix_3 * matrix_3_identity (matrix_3 * destination) { + destination = matrix_3_nullify (destination); + + for (natural index = 0; index < 3; ++index) { + destination [index] [index] = 1.0f; + } + + return (destination); +} + +static matrix_4 * matrix_4_identity (matrix_4 * destination) { + destination = matrix_4_nullify (destination); + + for (natural index = 0; index < 4; ++index) { + destination [index] [index] = 1.0f; + } + + return (destination); +} + +/// Return determinant of 2D, 3D or 4D matrix. + +static real matrix_2_determinant (matrix_2 * matrix) { + real a = matrix [0] [0] * matrix [1] [1]; + real b = matrix [0] [1] * matrix [1] [0]; + + return (a - b); +} + +static real matrix_3_determinant (matrix_3 * matrix) { + matrix_2 matrix_a = { { matrix [1] [1], matrix [1] [2] }, + { matrix [2] [1], matrix [2] [2] } }; + matrix_2 matrix_b = { { matrix [1] [0], matrix [1] [2] }, + { matrix [2] [0], matrix [2] [2] } }; + matrix_2 matrix_c = { { matrix [1] [0], matrix [1] [1] }, + { matrix [2] [0], matrix [2] [1] } }; + + real a = matrix [0] [0] * matrix_2_determinant (& matrix_a); + real b = matrix [0] [1] * matrix_2_determinant (& matrix_b); + real c = matrix [0] [2] * matrix_2_determinant (& matrix_c); + + return (a - b + c); +} + +static real matrix_4_determinant (matrix_4 * matrix) { + matrix_3 matrix_a = { { matrix [1] [1], matrix [1] [2], matrix [1] [3] }, + { matrix [2] [1], matrix [2] [2], matrix [2] [3] }, + { matrix [3] [1], matrix [3] [2], matrix [3] [3] } }; + matrix_3 matrix_b = { { matrix [1] [0], matrix [1] [2], matrix [1] [3] }, + { matrix [2] [0], matrix [2] [2], matrix [2] [3] }, + { matrix [3] [0], matrix [3] [2], matrix [3] [3] } }; + matrix_3 matrix_c = { { matrix [1] [0], matrix [1] [1], matrix [1] [3] }, + { matrix [2] [0], matrix [2] [1], matrix [2] [3] }, + { matrix [3] [0], matrix [3] [1], matrix [3] [3] } }; + matrix_3 matrix_d = { { matrix [1] [0], matrix [1] [1], matrix [1] [2] }, + { matrix [2] [0], matrix [2] [1], matrix [2] [2] }, + { matrix [3] [0], matrix [3] [1], matrix [3] [2] } }; + + real a = matrix [0] [0] * matrix_3_determinant (& matrix_a); + real b = matrix [0] [1] * matrix_3_determinant (& matrix_b); + real c = matrix [0] [2] * matrix_3_determinant (& matrix_c); + real d = matrix [0] [3] * matrix_3_determinant (& matrix_d); + + return (a - b + c - d); +} + +/// Copy 2D, 3D or 4D source matrix into destination matrix. + +static matrix_2 * matrix_2_copy (matrix_2 * destination, matrix_2 * source) { + for (natural row = 0; row < 2; ++row) { + for (natural column = 0; column < 2; ++column) { + destination [row] [column] = source [row] [column]; + } + } + + return (destination); +} + +static matrix_3 * matrix_3_copy (matrix_3 * destination, matrix_3 * source) { + for (natural row = 0; row < 3; ++row) { + for (natural column = 0; column < 3; ++column) { + destination [row] [column] = source [row] [column]; + } + } + + return (destination); +} + +static matrix_4 * matrix_4_copy (matrix_4 * destination, matrix_4 * source) { + for (natural row = 0; row < 4; ++row) { + for (natural column = 0; column < 4; ++column) { + destination [row] [column] = source [row] [column]; + } + } + + return (destination); +} + +/// Scale 2D, 3D or 4D matrix by scalar value and return address of that matrix. + +static matrix_2 * matrix_2_scale (matrix_2 * destination, real scale) { + for (natural row = 0; row < 2; ++row) { + for (natural column = 0; column < 2; ++column) { + destination [row] [column] *= scale; + } + } + + return (destination); +} + +static matrix_3 * matrix_3_scale (matrix_3 * destination, real scale) { + for (natural row = 0; row < 3; ++row) { + for (natural column = 0; column < 3; ++column) { + destination [row] [column] *= scale; + } + } + + return (destination); +} + +static matrix_4 * matrix_4_scale (matrix_4 * destination, real scale) { + for (natural row = 0; row < 4; ++row) { + for (natural column = 0; column < 4; ++column) { + destination [row] [column] *= scale; + } + } + + return (destination); +} + +/// Scale 2D, 3D or 4D source matrix by scalar value into destination matrix and return its address. + +static matrix_2 * matrix_2_scale_to (matrix_2 * destination, matrix_2 * source, real scale) { + for (natural row = 0; row < 2; ++row) { + for (natural column = 0; column < 2; ++column) { + destination [row] [column] = source [row] [column] * scale; + } + } + + return (destination); +} + +static matrix_3 * matrix_3_scale_to (matrix_3 * destination, matrix_3 * source, real scale) { + for (natural row = 0; row < 3; ++row) { + for (natural column = 0; column < 3; ++column) { + destination [row] [column] = source [row] [column] * scale; + } + } + + return (destination); +} + +static matrix_4 * matrix_4_scale_to (matrix_4 * destination, matrix_4 * source, real scale) { + for (natural row = 0; row < 4; ++row) { + for (natural column = 0; column < 4; ++column) { + destination [row] [column] = source [row] [column] * scale; + } + } + + return (destination); +} + +/// Add 2D, 3D or 4D source matrix onto destination matrix and return address of destination matrix. + +static matrix_2 * matrix_2_add (matrix_2 * destination, matrix_2 * source) { + for (natural row = 0; row < 2; ++row) { + for (natural column = 0; column < 2; ++column) { + destination [row] [column] += source [row] [column]; + } + } + + return (destination); +} + +static matrix_3 * matrix_3_add (matrix_3 * destination, matrix_3 * source) { + for (natural row = 0; row < 3; ++row) { + for (natural column = 0; column < 3; ++column) { + destination [row] [column] += source [row] [column]; + } + } + + return (destination); +} + +static matrix_4 * matrix_4_add (matrix_4 * destination, matrix_4 * source) { + for (natural row = 0; row < 4; ++row) { + for (natural column = 0; column < 4; ++column) { + destination [row] [column] += source [row] [column]; + } + } + + return (destination); +} + +/// Add two 2D, 3D or 4D matrices into destination matrix and return address of destination matrix. + +static matrix_2 * matrix_2_add_to (matrix_2 * destination, matrix_2 * matrix_a, matrix_2 * matrix_b) { + for (natural row = 0; row < 2; ++row) { + for (natural column = 0; column < 2; ++column) { + destination [row] [column] = matrix_a [row] [column] + matrix_b [row] [column]; + } + } + + return (destination); +} + +static matrix_3 * matrix_3_add_to (matrix_3 * destination, matrix_3 * matrix_a, matrix_3 * matrix_b) { + for (natural row = 0; row < 3; ++row) { + for (natural column = 0; column < 3; ++column) { + destination [row] [column] = matrix_a [row] [column] + matrix_b [row] [column]; + } + } + + return (destination); +} + +static matrix_4 * matrix_4_add_to (matrix_4 * destination, matrix_4 * matrix_a, matrix_4 * matrix_b) { + for (natural row = 0; row < 4; ++row) { + for (natural column = 0; column < 4; ++column) { + destination [row] [column] = matrix_a [row] [column] + matrix_b [row] [column]; + } + } + + return (destination); +} + +/// Subtract 2D, 3D or 4D source matrix from destination matrix and return address of destination matrix. + +static matrix_2 * matrix_2_subtract (matrix_2 * destination, matrix_2 * source) { + for (natural row = 0; row < 2; ++row) { + for (natural column = 0; column < 2; ++column) { + destination [row] [column] -= source [row] [column]; + } + } + + return (destination); +} + +static matrix_3 * matrix_3_subtract (matrix_3 * destination, matrix_3 * source) { + for (natural row = 0; row < 3; ++row) { + for (natural column = 0; column < 3; ++column) { + destination [row] [column] -= source [row] [column]; + } + } + + return (destination); +} + +static matrix_4 * matrix_4_subtract (matrix_4 * destination, matrix_4 * source) { + for (natural row = 0; row < 4; ++row) { + for (natural column = 0; column < 4; ++column) { + destination [row] [column] -= source [row] [column]; + } + } + + return (destination); +} + +/// Subtract two 2D, 3D or 4D matrices, save values into destination matrix and return address of destination matrix. + +static matrix_2 * matrix_2_subtract_to (matrix_2 * destination, matrix_2 * matrix_a, matrix_2 * matrix_b) { + for (natural row = 0; row < 2; ++row) { + for (natural column = 0; column < 2; ++column) { + destination [row] [column] = matrix_a [row] [column] - matrix_b [row] [column]; + } + } + + return (destination); +} + +static matrix_3 * matrix_3_subtract_to (matrix_3 * destination, matrix_3 * matrix_a, matrix_3 * matrix_b) { + for (natural row = 0; row < 3; ++row) { + for (natural column = 0; column < 3; ++column) { + destination [row] [column] = matrix_a [row] [column] - matrix_b [row] [column]; + } + } + + return (destination); +} + +static matrix_4 * matrix_4_subtract_to (matrix_4 * destination, matrix_4 * matrix_a, matrix_4 * matrix_b) { + for (natural row = 0; row < 4; ++row) { + for (natural column = 0; column < 4; ++column) { + destination [row] [column] = matrix_a [row] [column] - matrix_b [row] [column]; + } + } + + return (destination); +} + +/// Multiply two 2D, 3D or 4D matrices, save values into destination matrix and return address of destination matrix. + +static matrix_2 * matrix_2_multiply (matrix_2 * result, matrix_2 * matrix_a, matrix_2 * matrix_b) { + for (natural row = 0; row < 2; ++row) { + for (natural column = 0; column < 2; ++column) { + result [row] [column] = 0.0f; + + for (natural index = 0; index < 2; ++index) { + result [row] [column] += matrix_a [row] [index] * matrix_b [index] [column]; + } + } + } + + return (result); +} + +static matrix_3 * matrix_3_multiply (matrix_3 * result, matrix_3 * matrix_a, matrix_3 * matrix_b) { + for (natural row = 0; row < 3; ++row) { + for (natural column = 0; column < 3; ++column) { + result [row] [column] = 0.0f; + + for (natural index = 0; index < 3; ++index) { + result [row] [column] += matrix_a [row] [index] * matrix_b [index] [column]; + } + } + } + + return (result); +} + +static matrix_4 * matrix_4_multiply (matrix_4 * result, matrix_4 * matrix_a, matrix_4 * matrix_b) { + for (natural row = 0; row < 4; ++row) { + for (natural column = 0; column < 4; ++column) { + result [row] [column] = 0.0f; + + for (natural index = 0; index < 4; ++index) { + result [row] [column] += matrix_a [row] [index] * matrix_b [index] [column]; + } + } + } + + return (result); +} + +/// Return trace of 2D, 3D or 4D matrix. + +static real matrix_2_trace (matrix_2 * matrix) { + return (matrix [0] [0] + matrix [1] [1]); +} + +static real matrix_3_trace (matrix_3 * matrix) { + return (matrix [0] [0] + matrix [1] [1] + matrix [2] [2]); +} + +static real matrix_4_trace (matrix_4 * matrix) { + return (matrix [0] [0] + matrix [1] [1] + matrix [2] [2] + matrix [3] [3]); +} + +/// Compare if two 2D, 3D or 4D matrices are identical and return boolean value of it. + +static boolean matrix_2_compare (matrix_2 * matrix_a, matrix_2 * matrix_b) { + for (natural row = 0; row < 2; ++row) { + for (natural column = 0; column < 2; ++column) { + if (matrix_a [row] [column] != matrix_b [row] [column]) { + return (false); + } + } + } + + return (true); +} + +static boolean matrix_3_compare (matrix_3 * matrix_a, matrix_3 * matrix_b) { + for (natural row = 0; row < 3; ++row) { + for (natural column = 0; column < 3; ++column) { + if (matrix_a [row] [column] != matrix_b [row] [column]) { + return (false); + } + } + } + + return (true); +} + +static boolean matrix_4_compare (matrix_4 * matrix_a, matrix_4 * matrix_b) { + for (natural row = 0; row < 4; ++row) { + for (natural column = 0; column < 4; ++column) { + if (matrix_a [row] [column] != matrix_b [row] [column]) { + return (false); + } + } + } + + return (true); +} diff --git a/xector.h b/xector.h new file mode 100644 index 0000000..343a29d --- /dev/null +++ b/xector.h @@ -0,0 +1,438 @@ +/// _ +/// __ _____ ___| |_ ___ _ __ +/// \ \/ / _ \/ __| __/ _ \| '__| +/// > < __/ (__| || (_) | | +/// /_/\_\___|\___|\__\___/|_| +/// +/// Copyright (c) 1997 - Ognjen 'xolatile' Milan Robovic +/// +/// xolatile@chud.cyou - xector - Very slow and dumb vector library, mathematical vector, not that C++ cancer by the way... +/// +/// This program is free software, free as in freedom and as in free beer, you can redistribute it and/or modify it under the terms of the GNU +/// General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version if you wish... +/// +/// This program is distributed in the hope that it will be useful, but it is probably not, and without any warranty, without even the implied +/// warranty of merchantability or fitness for a particular purpose, because it is pointless. Please see the GNU (Geenoo) General Public License +/// for more details, if you dare, it is a lot of text that nobody wants to read... + +/// Description +/// +/// Xector (Vector), my small vector library, not to be confused with my older project Xector (Sector) which was for procedurally generating 3D +/// models (based on boolean operations on 3D sectors). This library isn't optimized for performance or memory usage, instead it's for my own +/// preferred programming style. It's hard to explain linear algebra to people who don't already know it (for me at least), so I won't do that, +/// function names should provide you enough information. There'll be simple comments for the sake of consistency with my other libraries. +/// +/// If you want to use "good" linear algebra library, prefer CGLM over this, and GLM if you're into C++ rather than objectively better language +/// called C. Again, reading comments in this file is useless. Include it, set the vectors, do the work. + +/// 2D vector structure. + +typedef struct { + real x, y; /// Two 32-bit floating point numbers. +} vector_2; + +/// 3D vector structure. + +typedef struct { + real x, y, z; /// Three 32-bit floating point numbers. +} vector_3; + +/// 4D vector structure. + +typedef struct { + real x, y, z, w; /// Why the hell did they choose to start from 'x', and end with 'z', it's so retarded. +} vector_4; + +/// Assign values to 2D, 3D or 4D vector and return address of that vector. + +static vector_2 * vector_2_assign (vector_2 * destination, real x, real y) { + destination->x = x; + destination->y = y; + + return (destination); +} + +static vector_3 * vector_3_assign (vector_3 * destination, real x, real y, real z) { + destination->x = x; + destination->y = y; + destination->z = z; + + return (destination); +} + +static vector_4 * vector_4_assign (vector_4 * destination, real x, real y, real z, real w) { + destination->x = x; + destination->y = y; + destination->z = z; + destination->w = w; + + return (destination); +} + +/// Nullify values of 2D, 3D or 4D vector and return address of that vector. + +static vector_2 * vector_2_nullify (vector_2 * destination) { + destination->x = destination->y = 0.0f; + + return (destination); +} + +static vector_3 * vector_3_nullify (vector_3 * destination) { + destination->x = destination->y = destination->z = 0.0f; + + return (destination); +} + +static vector_4 * vector_4_nullify (vector_4 * destination) { + destination->x = destination->y = destination->z = destination->w = 0.0f; + + return (destination); +} + +/// Return length of 2D, 3D or 4D vector. + +static real vector_2_length (vector_2 * vector) { + real x = vector->x; + real y = vector->y; + + return (square_root (x * x + y * y)); +} + +static real vector_3_length (vector_3 * vector) { + real x = vector->x; + real y = vector->y; + real z = vector->z; + + return (square_root (x * x + y * y + z * z)); +} + +static real vector_4_length (vector_4 * vector) { + real x = vector->x; + real y = vector->y; + real z = vector->z; + real w = vector->w; + + return (square_root (x * x + y * y + z * z + w * w)); +} + +/// Normalize 2D, 3D or 4D vector and return address of that vector. + +static vector_2 * vector_2_normalize (vector_2 * destination) { + real length = vector_2_length (destination); + + destination->x /= length; + destination->y /= length; + + return (destination); +} + +static vector_3 * vector_3_normalize (vector_3 * destination) { + real length = vector_3_length (destination); + + destination->x /= length; + destination->y /= length; + destination->z /= length; + + return (destination); +} + +static vector_4 * vector_4_normalize (vector_4 * destination) { + real length = vector_4_length (destination); + + destination->x /= length; + destination->y /= length; + destination->z /= length; + destination->w /= length; + + return (destination); +} + +/// Normalize 2D, 3D or 4D source vector into destination vector and return its address. + +static vector_2 * vector_2_normalize_to (vector_2 * destination, vector_2 * source) { + real length = vector_2_length (source); + + destination->x = source->x / length; + destination->y = source->y / length; + + return (destination); +} + +static vector_3 * vector_3_normalize_to (vector_3 * destination, vector_3 * source) { + real length = vector_3_length (source); + + destination->x = source->x / length; + destination->y = source->y / length; + destination->z = source->z / length; + + return (destination); +} + +static vector_4 * vector_4_normalize_to (vector_4 * destination, vector_4 * source) { + real length = vector_4_length (source); + + destination->x = source->x / length; + destination->y = source->y / length; + destination->z = source->z / length; + destination->w = source->w / length; + + return (destination); +} + +/// Copy 2D, 3D or 4D source vector into destination vector. + +static vector_2 * vector_2_copy (vector_2 * destination, vector_2 * source) { + destination->x = source->x; + destination->y = source->y; + + return (destination); +} + +static vector_3 * vector_3_copy (vector_3 * destination, vector_3 * source) { + destination->x = source->x; + destination->y = source->y; + destination->z = source->z; + + return (destination); +} + +static vector_4 * vector_4_copy (vector_4 * destination, vector_4 * source) { + destination->x = source->x; + destination->y = source->y; + destination->z = source->z; + destination->w = source->w; + + return (destination); +} + +/// Exchange values of two 2D, 3D or 4D vectors. + +static procedure vector_2_exchange (vector_2 * vector_a, vector_2 * vector_b) { + exchange_real (& vector_a->x, & vector_b->x); + exchange_real (& vector_a->y, & vector_b->y); +} + +static procedure vector_3_exchange (vector_3 * vector_a, vector_3 * vector_b) { + exchange_real (& vector_a->x, & vector_b->x); + exchange_real (& vector_a->y, & vector_b->y); + exchange_real (& vector_a->z, & vector_b->z); +} + +static procedure vector_4_exchange (vector_4 * vector_a, vector_4 * vector_b) { + exchange_real (& vector_a->x, & vector_b->x); + exchange_real (& vector_a->y, & vector_b->y); + exchange_real (& vector_a->z, & vector_b->z); + exchange_real (& vector_a->w, & vector_b->w); +} + +/// Scale 2D, 3D or 4D vector by scalar value and return address of that vector. + +static vector_2 * vector_2_scale (vector_2 * destination, real scale) { + destination->x *= scale; + destination->y *= scale; + + return (destination); +} + +static vector_3 * vector_3_scale (vector_3 * destination, real scale) { + destination->x *= scale; + destination->y *= scale; + destination->z *= scale; + + return (destination); +} + +static vector_4 * vector_4_scale (vector_4 * destination, real scale) { + destination->x *= scale; + destination->y *= scale; + destination->z *= scale; + destination->w *= scale; + + return (destination); +} + +/// Scale 2D, 3D or 4D source vector by scalar value into destination vector and return its address. + +static vector_2 * vector_2_scale_to (vector_2 * destination, vector_2 * source, real scale) { + destination->x = source->x * scale; + destination->y = source->y * scale; + + return (destination); +} + +static vector_3 * vector_3_scale_to (vector_3 * destination, vector_3 * source, real scale) { + destination->x = source->x * scale; + destination->y = source->y * scale; + destination->z = source->z * scale; + + return (destination); +} + +static vector_4 * vector_4_scale_to (vector_4 * destination, vector_4 * source, real scale) { + destination->x = source->x * scale; + destination->y = source->y * scale; + destination->z = source->z * scale; + destination->w = source->w * scale; + + return (destination); +} + +/// Add 2D, 3D or 4D source vector onto destination vector and return address of destination vector. + +static vector_2 * vector_2_add (vector_2 * destination, vector_2 * source) { + destination->x += source->x; + destination->y += source->y; + + return (destination); +} + +static vector_3 * vector_3_add (vector_3 * destination, vector_3 * source) { + destination->x += source->x; + destination->y += source->y; + destination->z += source->z; + + return (destination); +} + +static vector_4 * vector_4_add (vector_4 * destination, vector_4 * source) { + destination->x += source->x; + destination->y += source->y; + destination->z += source->z; + destination->w += source->w; + + return (destination); +} + +/// Add two 2D, 3D or 4D vectors into destination vector and return address of destination vector. + +static vector_2 * vector_2_add_to (vector_2 * destination, vector_2 * vector_a, vector_2 * vector_b) { + destination->x = vector_a->x + vector_b->x; + destination->y = vector_a->y + vector_b->y; + + return (destination); +} + +static vector_3 * vector_3_add_to (vector_3 * destination, vector_3 * vector_a, vector_3 * vector_b) { + destination->x = vector_a->x + vector_b->x; + destination->y = vector_a->y + vector_b->y; + destination->z = vector_a->z + vector_b->z; + + return (destination); +} + +static vector_4 * vector_4_add_to (vector_4 * destination, vector_4 * vector_a, vector_4 * vector_b) { + destination->x = vector_a->x + vector_b->x; + destination->y = vector_a->y + vector_b->y; + destination->z = vector_a->z + vector_b->z; + destination->w = vector_a->w + vector_b->w; + + return (destination); +} + +/// Subtract 2D, 3D or 4D source vector from destination vector and return address of destination vector. + +static vector_2 * vector_2_subtract (vector_2 * destination, vector_2 * source) { + destination->x -= source->x; + destination->y -= source->y; + + return (destination); +} + +static vector_3 * vector_3_subtract (vector_3 * destination, vector_3 * source) { + destination->x -= source->x; + destination->y -= source->y; + destination->z -= source->z; + + return (destination); +} + +static vector_4 * vector_4_subtract (vector_4 * destination, vector_4 * source) { + destination->x -= source->x; + destination->y -= source->y; + destination->z -= source->z; + destination->w -= source->w; + + return (destination); +} + +/// Subtract two 2D, 3D or 4D vectors, save values into destination vector and return address of destination vector. + +static vector_2 * vector_2_subtract_to (vector_2 * destination, vector_2 * vector_a, vector_2 * vector_b) { + destination->x = vector_a->x - vector_b->x; + destination->y = vector_a->y - vector_b->y; + + return (destination); +} + +static vector_3 * vector_3_subtract_to (vector_3 * destination, vector_3 * vector_a, vector_3 * vector_b) { + destination->x = vector_a->x - vector_b->x; + destination->y = vector_a->y - vector_b->y; + destination->z = vector_a->z - vector_b->z; + + return (destination); +} + +static vector_4 * vector_4_subtract_to (vector_4 * destination, vector_4 * vector_a, vector_4 * vector_b) { + destination->x = vector_a->x - vector_b->x; + destination->y = vector_a->y - vector_b->y; + destination->z = vector_a->z - vector_b->z; + destination->w = vector_a->w - vector_b->w; + + return (destination); +} + +/// Compare if two 2D, 3D or 4D vectors are identical and return boolean value of it. + +static boolean vector_2_compare (vector_2 * vector_a, vector_2 * vector_b) { + if ((vector_a->x == vector_b->x) && (vector_a->y == vector_b->y)) { + return (true); + } else { + return (false); + } +} + +static boolean vector_3_compare (vector_3 * vector_a, vector_3 * vector_b) { + if ((vector_a->x == vector_b->x) && (vector_a->y == vector_b->y) && (vector_a->z == vector_b->z)) { + return (true); + } else { + return (false); + } +} + +static boolean vector_4_compare (vector_4 * vector_a, vector_4 * vector_b) { + if ((vector_a->x == vector_b->x) && (vector_a->y == vector_b->y) && (vector_a->z == vector_b->z) && (vector_a->w == vector_b->w)) { + return (true); + } else { + return (false); + } +} + +/// Return dot product of two 2D, 3D or 4D vectors. + +static real vector_2_dot_product (vector_2 * vector_a, vector_2 * vector_b) { + return (vector_a->x * vector_b->x + vector_a->y * vector_b->y); +} + +static real vector_3_dot_product (vector_3 * vector_a, vector_3 * vector_b) { + return (vector_a->x * vector_b->x + vector_a->y * vector_b->y + vector_a->z * vector_b->z); +} + +static real vector_4_dot_product (vector_4 * vector_a, vector_4 * vector_b) { + return (vector_a->x * vector_b->x + vector_a->y * vector_b->y + vector_a->z * vector_b->z + vector_a->w * vector_b->w); +} + +/// Return cross product of two 2D vectors. + +static real vector_2_cross_product (vector_2 * vector_a, vector_2 * vector_b) { + return (vector_a->x * vector_b->y - vector_a->y * vector_b->x); +} + +/// Return cross product of two 3D vectors. + +static vector_3 * vector_3_cross_product (vector_3 * destination, vector_3 * source) { + destination->x = destination->y * source->z - destination->z * source->y; + destination->y = destination->z * source->x - destination->x * source->z; + destination->z = destination->x * source->y - destination->y * source->x; + + return (destination); +} diff --git a/xrena.h b/xrena.h new file mode 100644 index 0000000..16adb80 --- /dev/null +++ b/xrena.h @@ -0,0 +1,164 @@ +/// __ ___ __ ___ _ __ __ _ +/// \ \/ / '__/ _ \ '_ \ / _` | +/// > <| | | __/ | | | (_| | +/// /_/\_\_| \___|_| |_|\__,_| +/// +/// Copyright (c) 1997 - Ognjen 'xolatile' Milan Robovic +/// +/// xolatile@chud.cyou - xrena - Probably the most minimalistic arena allocator possible, and undoubtedly evil in implementation details. +/// +/// This program is free software, free as in freedom and as in free beer, you can redistribute it and/or modify it under the terms of the GNU +/// General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version if you wish... +/// +/// This program is distributed in the hope that it will be useful, but it is probably not, and without any warranty, without even the implied +/// warranty of merchantability or fitness for a particular purpose, because it is pointless. Please see the GNU (Geenoo) General Public License +/// for more details, if you dare, it is a lot of text that nobody wants to read... + +/// Description +/// +/// Xrena, extremely small header only library serving as arena allocator, with one global variable.In order to use it, include this header file, +/// there's no macro for including implementation (like stb libraries), this is for projects that have only one C source file, and one or more C +/// header files. I'll provide minimal examples below. + +/// Maximum size for single memory "allocation", if you're making a parser, you can use as low as 8 or 16, but as soon as you start working with +/// bigger structures, images or models, you need this to be higher value, for example 64 * 1024 * 1024 (loading 4k textures). If you don't +/// understand how to use this macro, turn off your machine and read some books, or alternatively, fuck around until you find out. + +#ifndef arena_block_limit +#define arena_block_limit (1024 * 1024) +#endif + +/// Structure and global variable definition, you shouldn't ever modify this, functions below cover that task. + +static struct { + caliber block_count; + caliber block_limit; + struct { + caliber count; + caliber capacity; + character * buffer; + } * * block_array; +} * arena_memory = null; + +/// Warning: Local function! You don't need to use this at all, it's covered by other functions, don't worry about it. +/// +/// This function will initialize the state of variable 'arena_memory', or extend it's size once memory is filled. + +static procedure arena_begin_or_widen (none) { + caliber current = ++arena_memory->block_count - 1; + + arena_memory->block_limit = arena_block_limit; + + arena_memory->block_array = reallocate (arena_memory->block_array, arena_memory->block_count * sizeof (* arena_memory->block_array)); + + arena_memory->block_array [current] = allocate (sizeof (* arena)); + + arena_memory->block_array [current]->buffer = allocate (arena_block_limit); + arena_memory->block_array [current]->count = 0; + arena_memory->block_array [current]->capacity = arena_block_limit; +} + +/// Warning: Local function! You don't need to use this at all, it's covered by other functions, don't worry about it. +/// +/// This function will clean all memory pools from variable 'arena_memory', freeing all memory used by the arena allocator. + +static procedure arena_clean (none) { + for (caliber index = 0; index < arena_memory->block_count; ++index) { + arena_memory->block_array [index]->buffer = deallocate (arena_memory->block_array [index]->buffer); + arena_memory->block_array [index] = deallocate (arena_memory->block_array [index]); + } + + arena_memory->block_array = deallocate (arena_memory->block_array); + arena_memory = deallocate (arena_memory); +} + +/// Now, this is finally a function that you want to use. You want to allocate object of some size, just add that size in arena, it'll return +/// you a pointer to that memory location, the same way you'd use 'malloc', and that memory will be zero initialized (unlike 'malloc', just like +/// 'calloc'). You don't ever have to worry about freeing memory, if your program has definite exit routine. Internally, it checks if arena +/// allocator was initialized, if it was, it'll extend it if there's not enough memory and return that pointer, otherwise, it will initialize it +/// and set clean up call at exit. +/// +/// Make an array of 60 integers, they'll all be zero. +/// +/// integer * my_integers = arena_add (60 * sizeof (my_integers)); + +static generic * arena_add (caliber size) { + caliber current = arena_memory->block_count - 1; + + if (arena == null) { + clean_up (arena_clean); + + arena_memory = allocate (sizeof (* arena_memory)); + + arena_begin_or_widen (); + } + + fatal_failure (size > arena_memory->block_limit, "arena_add: Block limit reached."); + + if (arena_memory->block_array [current]->count + size > arena_memory->block_array [current]->capacity) { + arena_begin_or_widen (); + } + + arena_memory->block_array [current]->count += size; + + return ((generic *) & arena_memory->block_array [current]->buffer [arena_memory->block_array [current]->count - size]); +} + +/// Add null terminated string to arena memory. +/// +/// character * my_token = arena_add_string (parsed_token); + +static character * arena_add_string (character * string) { + character * pointer = arena_add (string_length (string) * sizeof (pointer)); + + string_copy (pointer, string); + + return (pointer); +} + +/// Add raw memory of certain size to arena memory. +/// +/// generic * my_model = arena_add_memory (raw_model_data, size_of_model_data); + +static generic * arena_add_memory (generic * memory, caliber size) { + generic * pointer = arena_add (size); + + memory_copy (pointer, memory, size); + + return (pointer); +} + +/// Add file data from certain path, specify file flags (similar to 'open' system call) and set if you want it to be null terminated. +/// +/// generic * my_binary_file = arena_add_file ("foo.bin", file_flag_read, false); +/// character * my_text_file = arena_add_file ("foo.txt", file_flag_read, true); + +static character * arena_add_file (character * path, integer flag, boolean null_terminate) { + integer file = -1; + caliber size = 0; + character * data = null; + + file = file_open (path, flag); + size = file_size (path) + (caliber) null_terminate; + data = arena_add (size); + + file_read (file, data, size - (caliber) null_terminate); + + file = file_close (file); + + return (data); +} + +/// Simple utility function that returns how many bytes have been added to arena allocator. +/// +/// print ("So far I used %l bytes of memory...\n", arena_usage ()); + +static caliber arena_usage (none) { + caliber usage = 0; + + for (caliber block = 0; block < arena_memory->block_count; ++block) { + usage += arena_memory->block_array [block]->count; + } + + return (usage); +} diff --git a/xyntax.h b/xyntax.h new file mode 100644 index 0000000..76c164a --- /dev/null +++ b/xyntax.h @@ -0,0 +1,238 @@ +/// _ +/// __ ___ _ _ __ | |_ __ ___ __ +/// \ \/ / | | | '_ \| __/ _` \ \/ / +/// > <| |_| | | | | || (_| |> < +/// /_/\_\\__, |_| |_|\__\__,_/_/\_\ +/// |___/ +/// +/// Copyright (c) 1997 - Ognjen 'xolatile' Milan Robovic +/// +/// xolatile@chud.cyou - xyntax - Tiny, unsafe and somewhat insane unity header for generic syntax definition. +/// +/// This program is free software, free as in freedom and as in free beer, you can redistribute it and/or modify it under the terms of the GNU +/// General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version if you wish... +/// +/// This program is distributed in the hope that it will be useful, but it is probably not, and without any warranty, without even the implied +/// warranty of merchantability or fitness for a particular purpose, because it is pointless. Please see the GNU (Geenoo) General Public License +/// for more details, if you dare, it is a lot of text that nobody wants to read... + +/// Description +/// +/// Xyntax, the most minimal text parser that can deal with syntax highlighting that I could've come up with, and the most generic name for it +/// also, it's rather slow, but if you're creating heavy duty program, you'd use heavy duty library for it. This library has only one header, so +/// it's easy to incorporate it into existing projects. If you want to see how it is used, check out simple examples below, if you want more +/// robust example, check out my other programs, Xarbon and Xighlight. +/// +/// For start, you want to include this header file, there's no macro for including implementation (like stb libraries), this is for projects +/// that have only one C source file, and one or more C header files. Then make global or local variable 'syntax_structure * whatever_syntax' +/// defined below, initialize it, define the rules, then in main loop select rule, do whatever you wanted, then deinitialize the structure. It's +/// simple, I'll provide minimal examples below. + +/// Structure for single syntax definition (array of rules), if you want to parse multiple languages simultaneously, use an array. +/// +/// syntax_structure * syntax = null; + +typedef struct { + natural count; /// Count of syntax rules used, maximum is set with limit below, if limit is 0, it'll allocate it dynamically. + natural limit; /// Preallocation limit for syntax rules, hardcode it if you don't want this to allocate memory dynamically. + boolean * enrange; /// Enrange rule, set to true if you want to begin matching by any character from 'begin' string below. + boolean * derange; /// Derange rule, set to true if you want to end matching by any character from 'end' string below. + character * * begin; /// String containing set of characters or full string for start of matching, correlating to 'enrange' above. + character * * end; /// String containing set of characters or full string for end of matching, correlating to 'derange' above. + character * escape; /// Escape character, which will skip one cycle in selection loop, then continue matching for 'end' string. + natural * colour; /// Colour for matched array of characters, can be anything, enumerated, literal, hardcoded... + natural * effect; /// Effect for matched array of characters, can be anything, enumerated, literal, hardcoded... +} syntax_structure; + +/// Initialize syntax structure before calling other functions that take it as an argument, set 'limit' to 0 if you want dynamic array of rules. +/// +/// syntax = syntax_initialize (0); + +static syntax_structure * syntax_initialize (natural limit) { + syntax_structure * syntax = allocate (sizeof (* syntax)); + + syntax->limit = limit; + + if (limit != 0) { + syntax->enrange = allocate (syntax->limit * sizeof (* syntax->enrange)); + syntax->derange = allocate (syntax->limit * sizeof (* syntax->derange)); + syntax->begin = allocate (syntax->limit * sizeof (* syntax->begin)); + syntax->end = allocate (syntax->limit * sizeof (* syntax->end)); + syntax->escape = allocate (syntax->limit * sizeof (* syntax->escape)); + syntax->colour = allocate (syntax->limit * sizeof (* syntax->colour)); + syntax->effect = allocate (syntax->limit * sizeof (* syntax->effect)); + } + + return (syntax); +} + +/// Deinitialize syntax structure after using it, in order to avoid memory leaks. +/// +/// syntax = syntax_deinitialize (syntax); + +static syntax_structure * syntax_deinitialize (syntax_structure * syntax) { + for (natural index = 0; index < syntax->count; ++index) { + syntax->begin [index] = deallocate (syntax->begin [index]); + syntax->end [index] = deallocate (syntax->end [index]); + } + + syntax->enrange = deallocate (syntax->enrange); + syntax->derange = deallocate (syntax->derange); + syntax->begin = deallocate (syntax->begin); + syntax->end = deallocate (syntax->end); + syntax->escape = deallocate (syntax->escape); + syntax->colour = deallocate (syntax->colour); + syntax->effect = deallocate (syntax->effect); + + return (deallocate (syntax)); +} + +/// Define single syntax rule, which will be added into array part of syntax structure, return value is index into that array. +/// +/// Take a look into few simple examples of defining some simplified rules of C programming language. +/// Two examples below show how to define multiline comments and strings, since these have priority, both enrange and derange are false. +/// +/// syntax_define (syntax, false, false, "/*", "*/", '\\', 1, 0); +/// syntax_define (syntax, false, false, "\"", "\"", '\\', 2, 0); +/// +/// Now we're defining syntax rule for one keyword, static, notice that end string contaings separator characters because derange is true. +/// +/// syntax_define (syntax, false, true, "static", "()[]{}.,:;<=>+*-/%!&~^?| \t\r\n", '\0', 3, 0); +/// +/// You can define brackets and operator characters separately, or if you want to, you can define some of them separately again. +/// +/// syntax_define (syntax, true, false, "()[]{}", "", '\0', 4, 0); +/// syntax_define (syntax, true, false, ".,:;<=>+*-/%!&~^?|", "", '\0', 5, 0); +/// +/// And lastly, we can define number selection like this below, by setting both enrange and derange as false. +/// +/// syntax_define (syntax, true, true, "0123456789", "()[]{}.,:;<=>+*-/%!&~^?| \t\r\n", '\0', 6, 0); +/// +/// I hope this is pretty clear, if you want to select a number, you start by matching any of digits provided above, and you end matching that +/// number by any character from 'end' string, if you want to support floating point numbers, you'd exclude '.' character, or alternatively add +/// letters f, u, l and whatever else your language supports (like in C/C++). However, this approach is too weak for detecting syntax errors, +/// you shouldn't use this library for robust linter or parser. + +static natural syntax_define (syntax_structure * syntax, boolean enrange, boolean derange, character * begin, character * end, character escape, + natural colour, natural effect) { + ++syntax->count; + + natural current = syntax->count - 1; + + fatal_failure (begin == null, "syntax_define: Begin string is null pointer."); + fatal_failure (end == null, "syntax_define: End string is null pointer."); + + fatal_failure (syntax->count >= syntax->limit, "syntax_define: Reached the hardcoded limit."); + + if (syntax->limit == 0) { + syntax->enrange = reallocate (syntax->enrange, syntax->count * sizeof (* syntax->enrange)); + syntax->derange = reallocate (syntax->derange, syntax->count * sizeof (* syntax->derange)); + syntax->begin = reallocate (syntax->begin, syntax->count * sizeof (* syntax->begin)); + syntax->end = reallocate (syntax->end, syntax->count * sizeof (* syntax->end)); + syntax->escape = reallocate (syntax->escape, syntax->count * sizeof (* syntax->escape)); + syntax->colour = reallocate (syntax->colour, syntax->count * sizeof (* syntax->colour)); + syntax->effect = reallocate (syntax->effect, syntax->count * sizeof (* syntax->effect)); + } + + syntax->begin [current] = allocate ((string_length (begin) + 1) * sizeof (* * syntax->begin)); + syntax->end [current] = allocate ((string_length (end) + 1) * sizeof (* * syntax->end)); + + syntax->enrange [current] = enrange; + syntax->derange [current] = derange; + syntax->escape [current] = escape; + syntax->colour [current] = colour; + syntax->effect [current] = effect; + + string_copy (syntax->begin [current], begin); + string_copy (syntax->end [current], end); + + return (current); +} + +/// After all syntax definitions have been defined, call this function inside your main loop, return value is index of selected rule. +/// +/// Now, imagine that 'buffer' is file you've loaded into memory, you have declared natural numbers 'offset', 'length' and 'select', and you've +/// properly initialized syntax structure 'syntax', defined its rules for wanted language(s), simple main loop would look like this: +/// +/// for (offset = 0; buffer [offset] != '\0'; offset += length) { +/// /// Notice that we're not incrementing 'offset', we're increasing it by 'length'. +/// select = syntax_select (syntax, & buffer [offset], & length); +/// if (select >= syntax->count) { +/// /// Syntax definition is incomplete, unknown sequence has been detected, either print nothing, or print default. +/// } else { +/// /// Print string of 'length', at '& buffer [offset]', using 'syntax->colour [select]' and 'syntax->effect [select]'. +/// /// Strings here aren't null terminated, you want to print sized string. +/// } +/// } + +static natural syntax_select (syntax_structure * syntax, character * string, natural * length) { + natural offset = 0; + natural subset = 0; + natural select = 0; + + for (; select != syntax->count; ++select) { + caliber begin_length = string_length (syntax->begin [select]); + + if (syntax->enrange [select] == false) { + if (syntax->derange [select] == false) { + if (string_compare_limit (string, syntax->begin [select], begin_length) == true) { + break; + } + } else { + if ((string_compare_limit (string, syntax->begin [select], begin_length) == true) + && (character_compare_array (string [offset + begin_length], syntax->end [select]) == true)) { + break; + } + } + } else { + for (subset = 0; subset != begin_length; ++subset) { + if (string [offset] == syntax->begin [select] [subset]) { + goto selected; + } + } + } + } + + selected: + + if (select >= syntax->count) { + * length = 1; + + return (syntax->count); + } + + caliber end_length = string_length (syntax->end [select]); + + for (offset = 1; string [offset - 1] != character_null; ++offset) { + if (string [offset] == syntax->escape [select]) { + ++offset; + continue; + } + + if (syntax->derange [select] == true) { + subset = 0; + if (end_length == 0) { + break; + } do { + if (string [offset] == syntax->end [select] [subset]) { + * length = offset; + goto finished; + } + } while (++subset != end_length); + } else { + if (end_length != 0) { + if (string_compare_limit (& string [offset], syntax->end [select], end_length)) { + * length = offset + end_length; + return (select); + } + } else { + * length = 1; + return (select); + } + } + } + + finished: + + return (select); +}